| 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 | #ifndef _SIDEEFFECTS_H_ |
| 6 | #define _SIDEEFFECTS_H_ |
| 7 | |
| 8 | //------------------------------------------------------------------------ |
| 9 | // LclVarSet: |
| 10 | // Represents a set of lclVars. Optimized for the case that the set |
| 11 | // never holds more than a single element. This type is used internally |
| 12 | // by `AliasSet` to track the sets of lclVars that are read and |
| 13 | // written for a given alias set. |
| 14 | // |
| 15 | class LclVarSet final |
| 16 | { |
| 17 | union { |
| 18 | hashBv* m_bitVector; |
| 19 | unsigned m_lclNum; |
| 20 | }; |
| 21 | |
| 22 | bool m_hasAnyLcl; |
| 23 | bool m_hasBitVector; |
| 24 | |
| 25 | public: |
| 26 | LclVarSet(); |
| 27 | |
| 28 | inline bool IsEmpty() const |
| 29 | { |
| 30 | return !m_hasAnyLcl || !m_hasBitVector || !m_bitVector->anySet(); |
| 31 | } |
| 32 | |
| 33 | void Add(Compiler* compiler, unsigned lclNum); |
| 34 | bool Intersects(const LclVarSet& other) const; |
| 35 | bool Contains(unsigned lclNum) const; |
| 36 | void Clear(); |
| 37 | }; |
| 38 | |
| 39 | //------------------------------------------------------------------------ |
| 40 | // AliasSet: |
| 41 | // Represents a set of reads and writes for the purposes of alias |
| 42 | // analysis. This type partitions storage into two categories: |
| 43 | // lclVars and addressable locations. The definition of the former is |
| 44 | // intuitive. The latter is the union of the set of address-exposed |
| 45 | // lclVars with the set of all other memory locations. Any memory |
| 46 | // access is assumed to alias any other memory access. |
| 47 | // |
| 48 | class AliasSet final |
| 49 | { |
| 50 | LclVarSet m_lclVarReads; |
| 51 | LclVarSet m_lclVarWrites; |
| 52 | |
| 53 | bool m_readsAddressableLocation; |
| 54 | bool m_writesAddressableLocation; |
| 55 | |
| 56 | public: |
| 57 | //------------------------------------------------------------------------ |
| 58 | // AliasSet::NodeInfo: |
| 59 | // Represents basic alias information for a single IR node. |
| 60 | // |
| 61 | class NodeInfo final |
| 62 | { |
| 63 | enum : unsigned |
| 64 | { |
| 65 | ALIAS_NONE = 0x0, |
| 66 | ALIAS_READS_ADDRESSABLE_LOCATION = 0x1, |
| 67 | ALIAS_WRITES_ADDRESSABLE_LOCATION = 0x2, |
| 68 | ALIAS_READS_LCL_VAR = 0x4, |
| 69 | ALIAS_WRITES_LCL_VAR = 0x8 |
| 70 | }; |
| 71 | |
| 72 | Compiler* m_compiler; |
| 73 | GenTree* m_node; |
| 74 | unsigned m_flags; |
| 75 | unsigned m_lclNum; |
| 76 | |
| 77 | public: |
| 78 | NodeInfo(Compiler* compiler, GenTree* node); |
| 79 | |
| 80 | inline Compiler* TheCompiler() const |
| 81 | { |
| 82 | return m_compiler; |
| 83 | } |
| 84 | |
| 85 | inline GenTree* Node() const |
| 86 | { |
| 87 | return m_node; |
| 88 | } |
| 89 | |
| 90 | inline bool ReadsAddressableLocation() const |
| 91 | { |
| 92 | return (m_flags & ALIAS_READS_ADDRESSABLE_LOCATION) != 0; |
| 93 | } |
| 94 | |
| 95 | inline bool WritesAddressableLocation() const |
| 96 | { |
| 97 | return (m_flags & ALIAS_WRITES_ADDRESSABLE_LOCATION) != 0; |
| 98 | } |
| 99 | |
| 100 | inline bool IsLclVarRead() const |
| 101 | { |
| 102 | return (m_flags & ALIAS_READS_LCL_VAR) != 0; |
| 103 | } |
| 104 | |
| 105 | inline bool IsLclVarWrite() const |
| 106 | { |
| 107 | return (m_flags & ALIAS_WRITES_LCL_VAR) != 0; |
| 108 | } |
| 109 | |
| 110 | inline unsigned LclNum() const |
| 111 | { |
| 112 | assert(IsLclVarRead() || IsLclVarWrite()); |
| 113 | return m_lclNum; |
| 114 | } |
| 115 | |
| 116 | inline bool WritesAnyLocation() const |
| 117 | { |
| 118 | return (m_flags & (ALIAS_WRITES_ADDRESSABLE_LOCATION | ALIAS_WRITES_LCL_VAR)) != 0; |
| 119 | } |
| 120 | }; |
| 121 | |
| 122 | AliasSet(); |
| 123 | |
| 124 | inline bool WritesAnyLocation() const |
| 125 | { |
| 126 | return m_writesAddressableLocation || !m_lclVarWrites.IsEmpty(); |
| 127 | } |
| 128 | |
| 129 | void AddNode(Compiler* compiler, GenTree* node); |
| 130 | bool InterferesWith(const AliasSet& other) const; |
| 131 | bool InterferesWith(const NodeInfo& node) const; |
| 132 | void Clear(); |
| 133 | }; |
| 134 | |
| 135 | //------------------------------------------------------------------------ |
| 136 | // SideEffectSet: |
| 137 | // Represents a set of side effects for the purposes of analyzing code |
| 138 | // motion. |
| 139 | // Note that for non-fixed-size frames without a frame pointer (currently |
| 140 | // x86-only), we don't track the modification of the stack level that occurs |
| 141 | // with a GT_PUTARG_STK as a side-effect. If we ever support general code |
| 142 | // reordering, that would have to be taken into account. As it happens, |
| 143 | // we currently do not reorder any other side-effecting nodes relative to |
| 144 | // these. |
| 145 | // |
| 146 | class SideEffectSet final |
| 147 | { |
| 148 | unsigned m_sideEffectFlags; // A mask of GTF_* flags that represents exceptional and barrier side effects. |
| 149 | AliasSet m_aliasSet; // An AliasSet that represents read and write side effects. |
| 150 | |
| 151 | template <typename TOtherAliasInfo> |
| 152 | bool InterferesWith(unsigned otherSideEffectFlags, const TOtherAliasInfo& otherAliasInfo, bool strict) const; |
| 153 | |
| 154 | public: |
| 155 | SideEffectSet(); |
| 156 | SideEffectSet(Compiler* compiler, GenTree* node); |
| 157 | |
| 158 | void AddNode(Compiler* compiler, GenTree* node); |
| 159 | bool InterferesWith(const SideEffectSet& other, bool strict) const; |
| 160 | bool InterferesWith(Compiler* compiler, GenTree* node, bool strict) const; |
| 161 | void Clear(); |
| 162 | }; |
| 163 | |
| 164 | #endif // _SIDEEFFECTS_H_ |
| 165 | |