1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
10 #include "sideeffects.h"
12 LclVarSet::LclVarSet() : m_bitVector(nullptr), m_hasAnyLcl(false), m_hasBitVector(false)
16 //------------------------------------------------------------------------
18 // Adds the given lclNum to the LclVarSet.
21 // compiler - The compiler context
22 // lclNum - The lclNum to add.
24 void LclVarSet::Add(Compiler* compiler, unsigned lclNum)
35 unsigned singleLclNum = m_lclNum;
36 m_bitVector = hashBv::Create(compiler);
37 m_bitVector->setBit(singleLclNum);
38 m_hasBitVector = true;
41 m_bitVector->setBit(lclNum);
45 //------------------------------------------------------------------------
46 // LclVarSet::Intersects:
47 // Returns true if this LclVarSet intersects with the given LclVarSet.
50 // other - The other lclVarSet.
52 bool LclVarSet::Intersects(const LclVarSet& other) const
54 // If neither set has ever contained anything, the sets do not intersect.
55 if (!m_hasAnyLcl || !other.m_hasAnyLcl)
60 // If this set is not represented by a bit vector, see if the single lclNum is contained in the other set.
63 if (!other.m_hasBitVector)
65 return m_lclNum == other.m_lclNum;
68 return other.m_bitVector->testBit(m_lclNum);
71 // If this set is represented by a bit vector but the other set is not, see if the single lclNum in the other
72 // set is contained in this set.
73 if (!other.m_hasBitVector)
75 return m_bitVector->testBit(other.m_lclNum);
78 // Both sets are represented by bit vectors. Check to see if they intersect.
79 return m_bitVector->Intersects(other.m_bitVector);
82 //------------------------------------------------------------------------
83 // LclVarSet::Contains:
84 // Returns true if this LclVarSet contains the given lclNum.
87 // lclNum - The lclNum in question.
89 bool LclVarSet::Contains(unsigned lclNum) const
91 // If this set has never contained anything, it does not contain the lclNum.
97 // If this set is not represented by a bit vector, see if its single lclNum is the same as the given lclNum.
100 return m_lclNum == lclNum;
103 // This set is represented by a bit vector. See if the bit vector contains the given lclNum.
104 return m_bitVector->testBit(lclNum);
107 //------------------------------------------------------------------------
109 // Clears the contents of this LclVarSet.
111 void LclVarSet::Clear()
116 m_bitVector->ZeroAll();
118 else if (m_hasAnyLcl)
125 : m_lclVarReads(), m_lclVarWrites(), m_readsAddressableLocation(false), m_writesAddressableLocation(false)
129 //------------------------------------------------------------------------
130 // AliasSet::NodeInfo::NodeInfo:
131 // Computes the alias info for a given node. Note that this does not
132 // include the set of lclVar accesses for a node unless the node is
133 // itself a lclVar access (e.g. a GT_LCL_VAR, GT_STORE_LCL_VAR, etc.).
136 // compiler - The compiler context.
137 // node - The node in question.
139 AliasSet::NodeInfo::NodeInfo(Compiler* compiler, GenTree* node)
140 : m_compiler(compiler), m_node(node), m_flags(0), m_lclNum(0)
144 // Calls are treated as reads and writes of addressable locations unless they are known to be pure.
145 if (node->AsCall()->IsPure(compiler))
147 m_flags = ALIAS_NONE;
151 m_flags = ALIAS_READS_ADDRESSABLE_LOCATION | ALIAS_WRITES_ADDRESSABLE_LOCATION;
154 else if (node->OperIsAtomicOp())
156 // Atomic operations both read and write addressable locations.
157 m_flags = ALIAS_READS_ADDRESSABLE_LOCATION | ALIAS_WRITES_ADDRESSABLE_LOCATION;
161 // Is the operation a write? If so, set `node` to the location that is being written to.
162 bool isWrite = false;
163 if (node->OperIsAssignment())
166 node = node->gtGetOp1();
168 else if (node->OperIsStore() || node->OperIsAtomicOp())
173 // `node` is the location being accessed. Determine whether or not it is a memory or local variable access, and if
174 // it is the latter, get the number of the lclVar.
175 bool isMemoryAccess = false;
176 bool isLclVarAccess = false;
178 if (node->OperIsIndir())
180 // If the indirection targets a lclVar, we can be more precise with regards to aliasing by treating the
181 // indirection as a lclVar access.
182 GenTree* address = node->AsIndir()->Addr();
183 if (address->OperIsLocalAddr())
185 isLclVarAccess = true;
186 lclNum = address->AsLclVarCommon()->GetLclNum();
190 isMemoryAccess = true;
193 else if (node->OperIsImplicitIndir())
195 isMemoryAccess = true;
197 else if (node->OperIsLocal())
199 isLclVarAccess = true;
200 lclNum = node->AsLclVarCommon()->GetLclNum();
204 // This is neither a memory nor a local var access.
205 m_flags = ALIAS_NONE;
209 assert(isMemoryAccess || isLclVarAccess);
211 // Now that we've determined whether or not this access is a read or a write and whether the accessed location is
212 // memory or a lclVar, determine whther or not the location is addressable and udpate the alias set.
213 const bool isAddressableLocation = isMemoryAccess || compiler->lvaTable[lclNum].lvAddrExposed;
217 if (isAddressableLocation)
219 m_flags |= ALIAS_READS_ADDRESSABLE_LOCATION;
224 m_flags |= ALIAS_READS_LCL_VAR;
230 if (isAddressableLocation)
232 m_flags |= ALIAS_WRITES_ADDRESSABLE_LOCATION;
237 m_flags |= ALIAS_WRITES_LCL_VAR;
243 //------------------------------------------------------------------------
244 // AliasSet::AddNode:
245 // Adds the given node's accesses to this AliasSet.
248 // compiler - The compiler context.
249 // node - The node to add to the set.
251 void AliasSet::AddNode(Compiler* compiler, GenTree* node)
253 // First, add all lclVar uses associated with the node to the set. This is necessary because the lclVar reads occur
254 // at the position of the user, not at the position of the GenTreeLclVar node.
255 node->VisitOperands([compiler, this](GenTree* operand) -> GenTree::VisitResult {
256 if (operand->OperIsLocalRead())
258 const unsigned lclNum = operand->AsLclVarCommon()->GetLclNum();
259 if (compiler->lvaTable[lclNum].lvAddrExposed)
261 m_readsAddressableLocation = true;
264 m_lclVarReads.Add(compiler, lclNum);
266 if (!operand->IsArgPlaceHolderNode() && operand->isContained())
268 AddNode(compiler, operand);
270 return GenTree::VisitResult::Continue;
273 NodeInfo nodeInfo(compiler, node);
274 if (nodeInfo.ReadsAddressableLocation())
276 m_readsAddressableLocation = true;
278 if (nodeInfo.WritesAddressableLocation())
280 m_writesAddressableLocation = true;
282 if (nodeInfo.IsLclVarRead())
284 m_lclVarReads.Add(compiler, nodeInfo.LclNum());
286 if (nodeInfo.IsLclVarWrite())
288 m_lclVarWrites.Add(compiler, nodeInfo.LclNum());
292 //------------------------------------------------------------------------
293 // AliasSet::InterferesWith:
294 // Returns true if the reads and writes in this alias set interfere
295 // with the given alias set.
297 // Two alias sets interfere under any of the following conditions:
298 // - Both sets write to any addressable location (e.g. the heap,
299 // address-exposed locals)
300 // - One set reads any addressable location and the other set writes
301 // any addressable location
302 // - Both sets write to the same lclVar
303 // - One set writes to a lclVar that is read by the other set
306 // other - The other alias set.
308 bool AliasSet::InterferesWith(const AliasSet& other) const
310 // If both sets write any addressable location, the sets interfere.
311 if (m_writesAddressableLocation && other.m_writesAddressableLocation)
316 // If one set writes any addressable location and the other reads any addressable location, the sets interfere.
317 if ((m_readsAddressableLocation && other.m_writesAddressableLocation) ||
318 (m_writesAddressableLocation && other.m_readsAddressableLocation))
323 // If the set of lclVars written by this alias set intersects with the set of lclVars accessed by the other alias
324 // set, the alias sets interfere.
325 if (m_lclVarWrites.Intersects(other.m_lclVarReads) || m_lclVarWrites.Intersects(other.m_lclVarWrites))
330 // If the set of lclVars read by this alias set intersects with the set of lclVars written by the other alias set,
331 // the alias sets interfere. Otherwise, the alias sets do not interfere.
332 return m_lclVarReads.Intersects(other.m_lclVarWrites);
335 //------------------------------------------------------------------------
336 // AliasSet::InterferesWith:
337 // Returns true if the reads and writes in this alias set interfere
338 // with those for the given node.
340 // An alias set interferes with a given node iff it interferes with the
341 // alias set for that node.
344 // other - The info for the node in question.
346 bool AliasSet::InterferesWith(const NodeInfo& other) const
348 // First check whether or not this set interferes with the lclVar uses associated with the given node.
349 if (m_writesAddressableLocation || !m_lclVarWrites.IsEmpty())
351 Compiler* compiler = other.TheCompiler();
352 for (GenTree* operand : other.Node()->Operands())
354 if (operand->OperIsLocalRead())
356 // If this set writes any addressable location and the node uses an address-exposed lclVar,
357 // the set interferes with the node.
358 const unsigned lclNum = operand->AsLclVarCommon()->GetLclNum();
359 if (compiler->lvaTable[lclNum].lvAddrExposed && m_writesAddressableLocation)
364 // If this set writes to a lclVar used by the node, the set interferes with the node.
365 if (m_lclVarWrites.Contains(lclNum))
373 // If the node and the set both write to any addressable location, they interfere.
374 if (m_writesAddressableLocation && other.WritesAddressableLocation())
379 // If the node or the set writes any addressable location and the other reads any addressable location,
381 if ((m_readsAddressableLocation && other.WritesAddressableLocation()) ||
382 (m_writesAddressableLocation && other.ReadsAddressableLocation()))
387 // If the set writes a local var accessed by the node, they interfere.
388 if ((other.IsLclVarRead() || other.IsLclVarWrite()) && m_lclVarWrites.Contains(other.LclNum()))
393 // If the set reads a local var written by the node, they interfere.
394 return other.IsLclVarWrite() && m_lclVarReads.Contains(other.LclNum());
397 //------------------------------------------------------------------------
399 // Clears the current alias set.
401 void AliasSet::Clear()
403 m_readsAddressableLocation = false;
404 m_writesAddressableLocation = false;
406 m_lclVarReads.Clear();
407 m_lclVarWrites.Clear();
410 SideEffectSet::SideEffectSet() : m_sideEffectFlags(0), m_aliasSet()
414 //------------------------------------------------------------------------
415 // SideEffectSet::SideEffectSet:
416 // Constructs a side effect set initialized using the given node.
417 // Equivalent to the following;
419 // SideEffectSet sideEffectSet;
420 // sideEffectSet.AddNode(compiler, node);
423 // compiler - The compiler context.
424 // node - The node to use for initialization.
426 SideEffectSet::SideEffectSet(Compiler* compiler, GenTree* node) : m_sideEffectFlags(0), m_aliasSet()
428 AddNode(compiler, node);
431 //------------------------------------------------------------------------
432 // SideEffectSet::AddNode:
433 // Adds the given node's accesses to this SideEffectSet.
436 // compiler - The compiler context.
437 // node - The node to add to the set.
439 void SideEffectSet::AddNode(Compiler* compiler, GenTree* node)
441 m_sideEffectFlags |= (node->gtFlags & GTF_ALL_EFFECT);
442 m_aliasSet.AddNode(compiler, node);
445 //------------------------------------------------------------------------
446 // SideEffectSet::InterferesWith:
447 // Returns true if the side effects in this set interfere with the
448 // given side effect flags and alias information.
450 // Two side effect sets interfere under any of the following
452 // - If the analysis is strict, and:
453 // - Either set contains a compiler barrier, or
454 // - Both sets produce an exception
455 // - Whether or not the analysis is strict:
456 // - One set produces an exception and the other set contains a
458 // - One set's reads and writes interfere with the other set's
462 // otherSideEffectFlags - The side effect flags for the other side
464 // otherAliasInfo - The alias information for the other side effect
466 // strict - True if the analysis should be strict as described above.
468 template <typename TOtherAliasInfo>
469 bool SideEffectSet::InterferesWith(unsigned otherSideEffectFlags,
470 const TOtherAliasInfo& otherAliasInfo,
473 const bool thisProducesException = (m_sideEffectFlags & GTF_EXCEPT) != 0;
474 const bool otherProducesException = (otherSideEffectFlags & GTF_EXCEPT) != 0;
478 // If either set contains a compiler barrier, the sets interfere.
479 if (((m_sideEffectFlags | otherSideEffectFlags) & GTF_ORDER_SIDEEFF) != 0)
484 // If both sets produce an exception, the sets interfere.
485 if (thisProducesException && otherProducesException)
491 // If one set produces an exception and the other set writes to any location, the sets interfere.
492 if ((thisProducesException && otherAliasInfo.WritesAnyLocation()) ||
493 (otherProducesException && m_aliasSet.WritesAnyLocation()))
498 // At this point, the only interference between the sets will arise from their alias sets.
499 return m_aliasSet.InterferesWith(otherAliasInfo);
502 //------------------------------------------------------------------------
503 // SideEffectSet::InterferesWith:
504 // Returns true if the side effects in this set interfere with the side
505 // effects in the given side effect set.
507 // Two side effect sets interfere under any of the following
509 // - If the analysis is strict, and:
510 // - Either set contains a compiler barrier, or
511 // - Both sets produce an exception
512 // - Whether or not the analysis is strict:
513 // - One set produces an exception and the other set contains a
515 // - One set's reads and writes interfere with the other set's
519 // other - The other side effect set.
520 // strict - True if the analysis should be strict as described above.
522 bool SideEffectSet::InterferesWith(const SideEffectSet& other, bool strict) const
524 return InterferesWith(other.m_sideEffectFlags, other.m_aliasSet, strict);
527 //------------------------------------------------------------------------
528 // SideEffectSet::InterferesWith:
529 // Returns true if the side effects in this set interfere with the side
530 // effects for the given node.
532 // A side effect set interferes with a given node iff it interferes
533 // with the side effect set of the node.
536 // compiler - The compiler context.
537 // node - The node in question.
538 // strict - True if the analysis should be strict as described above.
540 bool SideEffectSet::InterferesWith(Compiler* compiler, GenTree* node, bool strict) const
542 return InterferesWith((node->gtFlags & GTF_ALL_EFFECT), AliasSet::NodeInfo(compiler, node), strict);
545 //------------------------------------------------------------------------
546 // SideEffectSet::Clear:
547 // Clears the current side effect set.
549 void SideEffectSet::Clear()
551 m_sideEffectFlags = 0;