summaryrefslogtreecommitdiff
path: root/src/jit/sideeffects.h
blob: e14b2925ed79a8a8461090af4cdeb8c219089828 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef _SIDEEFFECTS_H_
#define _SIDEEFFECTS_H_

//------------------------------------------------------------------------
// LclVarSet:
//    Represents a set of lclVars. Optimized for the case that the set
//    never holds more than a single element. This type is used internally
//    by `AliasSet` to track the sets of lclVars that are read and
//    written for a given alias set.
//
class LclVarSet final
{
    union {
        hashBv*  m_bitVector;
        unsigned m_lclNum;
    };

    bool m_hasAnyLcl;
    bool m_hasBitVector;

public:
    LclVarSet();

    inline bool IsEmpty() const
    {
        return !m_hasAnyLcl || !m_hasBitVector || !m_bitVector->anySet();
    }

    void Add(Compiler* compiler, unsigned lclNum);
    bool Intersects(const LclVarSet& other) const;
    bool Contains(unsigned lclNum) const;
    void Clear();
};

//------------------------------------------------------------------------
// AliasSet:
//    Represents a set of reads and writes for the purposes of alias
//    analysis. This type partitions storage into two categories:
//    lclVars and addressable locations. The definition of the former is
//    intuitive. The latter is the union of the set of address-exposed
//    lclVars with the set of all other memory locations. Any memory
//    access is assumed to alias any other memory access.
//
class AliasSet final
{
    LclVarSet m_lclVarReads;
    LclVarSet m_lclVarWrites;

    bool m_readsAddressableLocation;
    bool m_writesAddressableLocation;

public:
    //------------------------------------------------------------------------
    // AliasSet::NodeInfo:
    //    Represents basic alias information for a single IR node.
    //
    class NodeInfo final
    {
        enum : unsigned
        {
            ALIAS_NONE                        = 0x0,
            ALIAS_READS_ADDRESSABLE_LOCATION  = 0x1,
            ALIAS_WRITES_ADDRESSABLE_LOCATION = 0x2,
            ALIAS_READS_LCL_VAR               = 0x4,
            ALIAS_WRITES_LCL_VAR              = 0x8
        };

        Compiler* m_compiler;
        GenTree*  m_node;
        unsigned  m_flags;
        unsigned  m_lclNum;

    public:
        NodeInfo(Compiler* compiler, GenTree* node);

        inline Compiler* TheCompiler() const
        {
            return m_compiler;
        }

        inline GenTree* Node() const
        {
            return m_node;
        }

        inline bool ReadsAddressableLocation() const
        {
            return (m_flags & ALIAS_READS_ADDRESSABLE_LOCATION) != 0;
        }

        inline bool WritesAddressableLocation() const
        {
            return (m_flags & ALIAS_WRITES_ADDRESSABLE_LOCATION) != 0;
        }

        inline bool IsLclVarRead() const
        {
            return (m_flags & ALIAS_READS_LCL_VAR) != 0;
        }

        inline bool IsLclVarWrite() const
        {
            return (m_flags & ALIAS_WRITES_LCL_VAR) != 0;
        }

        inline unsigned LclNum() const
        {
            assert(IsLclVarRead() || IsLclVarWrite());
            return m_lclNum;
        }

        inline bool WritesAnyLocation() const
        {
            return (m_flags & (ALIAS_WRITES_ADDRESSABLE_LOCATION | ALIAS_WRITES_LCL_VAR)) != 0;
        }
    };

    AliasSet();

    inline bool WritesAnyLocation() const
    {
        return m_writesAddressableLocation || !m_lclVarWrites.IsEmpty();
    }

    void AddNode(Compiler* compiler, GenTree* node);
    bool InterferesWith(const AliasSet& other) const;
    bool InterferesWith(const NodeInfo& node) const;
    void Clear();
};

//------------------------------------------------------------------------
// SideEffectSet:
//    Represents a set of side effects for the purposes of analyzing code
//    motion.
//    Note that for non-fixed-size frames without a frame pointer (currently
//    x86-only), we don't track the modification of the stack level that occurs
//    with a GT_PUTARG_STK as a side-effect. If we ever support general code
//    reordering, that would have to be taken into account. As it happens,
//    we currently do not reorder any other side-effecting nodes relative to
//    these.
//
class SideEffectSet final
{
    unsigned m_sideEffectFlags; // A mask of GTF_* flags that represents exceptional and barrier side effects.
    AliasSet m_aliasSet;        // An AliasSet that represents read and write side effects.

    template <typename TOtherAliasInfo>
    bool InterferesWith(unsigned otherSideEffectFlags, const TOtherAliasInfo& otherAliasInfo, bool strict) const;

public:
    SideEffectSet();
    SideEffectSet(Compiler* compiler, GenTree* node);

    void AddNode(Compiler* compiler, GenTree* node);
    bool InterferesWith(const SideEffectSet& other, bool strict) const;
    bool InterferesWith(Compiler* compiler, GenTree* node, bool strict) const;
    void Clear();
};

#endif // _SIDEEFFECTS_H_