Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / sideeffects.cpp
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.
4
5 #include "jitpch.h"
6 #ifdef _MSC_VER
7 #pragma hdrstop
8 #endif
9
10 #include "sideeffects.h"
11
12 LclVarSet::LclVarSet() : m_bitVector(nullptr), m_hasAnyLcl(false), m_hasBitVector(false)
13 {
14 }
15
16 //------------------------------------------------------------------------
17 // LclVarSet::Add:
18 //    Adds the given lclNum to the LclVarSet.
19 //
20 // Arguments:
21 //    compiler - The compiler context
22 //    lclNum - The lclNum to add.
23 //
24 void LclVarSet::Add(Compiler* compiler, unsigned lclNum)
25 {
26     if (!m_hasAnyLcl)
27     {
28         m_lclNum    = lclNum;
29         m_hasAnyLcl = true;
30     }
31     else
32     {
33         if (!m_hasBitVector)
34         {
35             unsigned singleLclNum = m_lclNum;
36             m_bitVector           = hashBv::Create(compiler);
37             m_bitVector->setBit(singleLclNum);
38             m_hasBitVector = true;
39         }
40
41         m_bitVector->setBit(lclNum);
42     }
43 }
44
45 //------------------------------------------------------------------------
46 // LclVarSet::Intersects:
47 //    Returns true if this LclVarSet intersects with the given LclVarSet.
48 //
49 // Arguments:
50 //    other - The other lclVarSet.
51 //
52 bool LclVarSet::Intersects(const LclVarSet& other) const
53 {
54     // If neither set has ever contained anything, the sets do not intersect.
55     if (!m_hasAnyLcl || !other.m_hasAnyLcl)
56     {
57         return false;
58     }
59
60     // If this set is not represented by a bit vector, see if the single lclNum is contained in the other set.
61     if (!m_hasBitVector)
62     {
63         if (!other.m_hasBitVector)
64         {
65             return m_lclNum == other.m_lclNum;
66         }
67
68         return other.m_bitVector->testBit(m_lclNum);
69     }
70
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)
74     {
75         return m_bitVector->testBit(other.m_lclNum);
76     }
77
78     // Both sets are represented by bit vectors. Check to see if they intersect.
79     return m_bitVector->Intersects(other.m_bitVector);
80 }
81
82 //------------------------------------------------------------------------
83 // LclVarSet::Contains:
84 //    Returns true if this LclVarSet contains the given lclNum.
85 //
86 // Arguments:
87 //    lclNum - The lclNum in question.
88 //
89 bool LclVarSet::Contains(unsigned lclNum) const
90 {
91     // If this set has never contained anything, it does not contain the lclNum.
92     if (!m_hasAnyLcl)
93     {
94         return false;
95     }
96
97     // If this set is not represented by a bit vector, see if its single lclNum is the same as the given lclNum.
98     if (!m_hasBitVector)
99     {
100         return m_lclNum == lclNum;
101     }
102
103     // This set is represented by a bit vector. See if the bit vector contains the given lclNum.
104     return m_bitVector->testBit(lclNum);
105 }
106
107 //------------------------------------------------------------------------
108 // LclVarSet::Clear:
109 //    Clears the contents of this LclVarSet.
110 //
111 void LclVarSet::Clear()
112 {
113     if (m_hasBitVector)
114     {
115         assert(m_hasAnyLcl);
116         m_bitVector->ZeroAll();
117     }
118     else if (m_hasAnyLcl)
119     {
120         m_hasAnyLcl = false;
121     }
122 }
123
124 AliasSet::AliasSet()
125     : m_lclVarReads(), m_lclVarWrites(), m_readsAddressableLocation(false), m_writesAddressableLocation(false)
126 {
127 }
128
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.).
134 //
135 // Arguments:
136 //    compiler - The compiler context.
137 //    node - The node in question.
138 //
139 AliasSet::NodeInfo::NodeInfo(Compiler* compiler, GenTree* node)
140     : m_compiler(compiler), m_node(node), m_flags(0), m_lclNum(0)
141 {
142     if (node->IsCall())
143     {
144         // Calls are treated as reads and writes of addressable locations unless they are known to be pure.
145         if (node->AsCall()->IsPure(compiler))
146         {
147             m_flags = ALIAS_NONE;
148             return;
149         }
150
151         m_flags = ALIAS_READS_ADDRESSABLE_LOCATION | ALIAS_WRITES_ADDRESSABLE_LOCATION;
152         return;
153     }
154     else if (node->OperIsAtomicOp())
155     {
156         // Atomic operations both read and write addressable locations.
157         m_flags = ALIAS_READS_ADDRESSABLE_LOCATION | ALIAS_WRITES_ADDRESSABLE_LOCATION;
158         return;
159     }
160
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())
164     {
165         isWrite = true;
166         node    = node->gtGetOp1();
167     }
168     else if (node->OperIsStore() || node->OperIsAtomicOp())
169     {
170         isWrite = true;
171     }
172
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;
177     unsigned lclNum         = 0;
178     if (node->OperIsIndir())
179     {
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())
184         {
185             isLclVarAccess = true;
186             lclNum         = address->AsLclVarCommon()->GetLclNum();
187         }
188         else
189         {
190             isMemoryAccess = true;
191         }
192     }
193     else if (node->OperIsImplicitIndir())
194     {
195         isMemoryAccess = true;
196     }
197     else if (node->OperIsLocal())
198     {
199         isLclVarAccess = true;
200         lclNum         = node->AsLclVarCommon()->GetLclNum();
201     }
202     else
203     {
204         // This is neither a memory nor a local var access.
205         m_flags = ALIAS_NONE;
206         return;
207     }
208
209     assert(isMemoryAccess || isLclVarAccess);
210
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;
214
215     if (!isWrite)
216     {
217         if (isAddressableLocation)
218         {
219             m_flags |= ALIAS_READS_ADDRESSABLE_LOCATION;
220         }
221
222         if (isLclVarAccess)
223         {
224             m_flags |= ALIAS_READS_LCL_VAR;
225             m_lclNum = lclNum;
226         }
227     }
228     else
229     {
230         if (isAddressableLocation)
231         {
232             m_flags |= ALIAS_WRITES_ADDRESSABLE_LOCATION;
233         }
234
235         if (isLclVarAccess)
236         {
237             m_flags |= ALIAS_WRITES_LCL_VAR;
238             m_lclNum = lclNum;
239         }
240     }
241 }
242
243 //------------------------------------------------------------------------
244 // AliasSet::AddNode:
245 //    Adds the given node's accesses to this AliasSet.
246 //
247 // Arguments:
248 //    compiler - The compiler context.
249 //    node - The node to add to the set.
250 //
251 void AliasSet::AddNode(Compiler* compiler, GenTree* node)
252 {
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())
257         {
258             const unsigned lclNum = operand->AsLclVarCommon()->GetLclNum();
259             if (compiler->lvaTable[lclNum].lvAddrExposed)
260             {
261                 m_readsAddressableLocation = true;
262             }
263
264             m_lclVarReads.Add(compiler, lclNum);
265         }
266         if (!operand->IsArgPlaceHolderNode() && operand->isContained())
267         {
268             AddNode(compiler, operand);
269         }
270         return GenTree::VisitResult::Continue;
271     });
272
273     NodeInfo nodeInfo(compiler, node);
274     if (nodeInfo.ReadsAddressableLocation())
275     {
276         m_readsAddressableLocation = true;
277     }
278     if (nodeInfo.WritesAddressableLocation())
279     {
280         m_writesAddressableLocation = true;
281     }
282     if (nodeInfo.IsLclVarRead())
283     {
284         m_lclVarReads.Add(compiler, nodeInfo.LclNum());
285     }
286     if (nodeInfo.IsLclVarWrite())
287     {
288         m_lclVarWrites.Add(compiler, nodeInfo.LclNum());
289     }
290 }
291
292 //------------------------------------------------------------------------
293 // AliasSet::InterferesWith:
294 //    Returns true if the reads and writes in this alias set interfere
295 //    with the given alias set.
296 //
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
304 //
305 // Arguments:
306 //    other - The other alias set.
307 //
308 bool AliasSet::InterferesWith(const AliasSet& other) const
309 {
310     // If both sets write any addressable location, the sets interfere.
311     if (m_writesAddressableLocation && other.m_writesAddressableLocation)
312     {
313         return true;
314     }
315
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))
319     {
320         return true;
321     }
322
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))
326     {
327         return true;
328     }
329
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);
333 }
334
335 //------------------------------------------------------------------------
336 // AliasSet::InterferesWith:
337 //    Returns true if the reads and writes in this alias set interfere
338 //    with those for the given node.
339 //
340 //    An alias set interferes with a given node iff it interferes with the
341 //    alias set for that node.
342 //
343 // Arguments:
344 //    other - The info for the node in question.
345 //
346 bool AliasSet::InterferesWith(const NodeInfo& other) const
347 {
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())
350     {
351         Compiler* compiler = other.TheCompiler();
352         for (GenTree* operand : other.Node()->Operands())
353         {
354             if (operand->OperIsLocalRead())
355             {
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)
360                 {
361                     return true;
362                 }
363
364                 // If this set writes to a lclVar used by the node, the set interferes with the node.
365                 if (m_lclVarWrites.Contains(lclNum))
366                 {
367                     return true;
368                 }
369             }
370         }
371     }
372
373     // If the node and the set both write to any addressable location, they interfere.
374     if (m_writesAddressableLocation && other.WritesAddressableLocation())
375     {
376         return true;
377     }
378
379     // If the node or the set writes any addressable location and the other reads any addressable location,
380     // they interfere.
381     if ((m_readsAddressableLocation && other.WritesAddressableLocation()) ||
382         (m_writesAddressableLocation && other.ReadsAddressableLocation()))
383     {
384         return true;
385     }
386
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()))
389     {
390         return true;
391     }
392
393     // If the set reads a local var written by the node, they interfere.
394     return other.IsLclVarWrite() && m_lclVarReads.Contains(other.LclNum());
395 }
396
397 //------------------------------------------------------------------------
398 // AliasSet::Clear:
399 //    Clears the current alias set.
400 //
401 void AliasSet::Clear()
402 {
403     m_readsAddressableLocation  = false;
404     m_writesAddressableLocation = false;
405
406     m_lclVarReads.Clear();
407     m_lclVarWrites.Clear();
408 }
409
410 SideEffectSet::SideEffectSet() : m_sideEffectFlags(0), m_aliasSet()
411 {
412 }
413
414 //------------------------------------------------------------------------
415 // SideEffectSet::SideEffectSet:
416 //    Constructs a side effect set initialized using the given node.
417 //    Equivalent to the following;
418 //
419 //       SideEffectSet sideEffectSet;
420 //       sideEffectSet.AddNode(compiler, node);
421 //
422 // Arguments:
423 //    compiler - The compiler context.
424 //    node - The node to use for initialization.
425 //
426 SideEffectSet::SideEffectSet(Compiler* compiler, GenTree* node) : m_sideEffectFlags(0), m_aliasSet()
427 {
428     AddNode(compiler, node);
429 }
430
431 //------------------------------------------------------------------------
432 // SideEffectSet::AddNode:
433 //    Adds the given node's accesses to this SideEffectSet.
434 //
435 // Arguments:
436 //    compiler - The compiler context.
437 //    node - The node to add to the set.
438 //
439 void SideEffectSet::AddNode(Compiler* compiler, GenTree* node)
440 {
441     m_sideEffectFlags |= (node->gtFlags & GTF_ALL_EFFECT);
442     m_aliasSet.AddNode(compiler, node);
443 }
444
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.
449 //
450 //    Two side effect sets interfere under any of the following
451 //    conditions:
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
457 //          write
458 //        - One set's reads and writes interfere with the other set's
459 //          reads and writes
460 //
461 // Arguments:
462 //    otherSideEffectFlags - The side effect flags for the other side
463 //                           effect set.
464 //    otherAliasInfo - The alias information for the other side effect
465 //                     set.
466 //    strict - True if the analysis should be strict as described above.
467 //
468 template <typename TOtherAliasInfo>
469 bool SideEffectSet::InterferesWith(unsigned               otherSideEffectFlags,
470                                    const TOtherAliasInfo& otherAliasInfo,
471                                    bool                   strict) const
472 {
473     const bool thisProducesException  = (m_sideEffectFlags & GTF_EXCEPT) != 0;
474     const bool otherProducesException = (otherSideEffectFlags & GTF_EXCEPT) != 0;
475
476     if (strict)
477     {
478         // If either set contains a compiler barrier, the sets interfere.
479         if (((m_sideEffectFlags | otherSideEffectFlags) & GTF_ORDER_SIDEEFF) != 0)
480         {
481             return true;
482         }
483
484         // If both sets produce an exception, the sets interfere.
485         if (thisProducesException && otherProducesException)
486         {
487             return true;
488         }
489     }
490
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()))
494     {
495         return true;
496     }
497
498     // At this point, the only interference between the sets will arise from their alias sets.
499     return m_aliasSet.InterferesWith(otherAliasInfo);
500 }
501
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.
506 //
507 //    Two side effect sets interfere under any of the following
508 //    conditions:
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
514 //          write
515 //        - One set's reads and writes interfere with the other set's
516 //          reads and writes
517 //
518 // Arguments:
519 //    other - The other side effect set.
520 //    strict - True if the analysis should be strict as described above.
521 //
522 bool SideEffectSet::InterferesWith(const SideEffectSet& other, bool strict) const
523 {
524     return InterferesWith(other.m_sideEffectFlags, other.m_aliasSet, strict);
525 }
526
527 //------------------------------------------------------------------------
528 // SideEffectSet::InterferesWith:
529 //    Returns true if the side effects in this set interfere with the side
530 //    effects for the given node.
531 //
532 //    A side effect set interferes with a given node iff it interferes
533 //    with the side effect set of the node.
534 //
535 // Arguments:
536 //    compiler - The compiler context.
537 //    node - The node in question.
538 //    strict - True if the analysis should be strict as described above.
539 //
540 bool SideEffectSet::InterferesWith(Compiler* compiler, GenTree* node, bool strict) const
541 {
542     return InterferesWith((node->gtFlags & GTF_ALL_EFFECT), AliasSet::NodeInfo(compiler, node), strict);
543 }
544
545 //------------------------------------------------------------------------
546 // SideEffectSet::Clear:
547 //    Clears the current side effect set.
548 //
549 void SideEffectSet::Clear()
550 {
551     m_sideEffectFlags = 0;
552     m_aliasSet.Clear();
553 }