summaryrefslogtreecommitdiff
path: root/src/jit/rationalize.h
blob: 6f2c1d8246175924a09a8933c9c6bf0dec88d33d (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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

//===============================================================================
#include "phase.h"

enum Rationalizations
{
    Questions = 0x1,
    NestedCalls = 0x2,
    NestedAssigns = 0x4,
    Commas = 0x8
};

//------------------------------------------------------------------------------
// Location - (tree, block) tuple is minimum context required to manipulate trees in the JIT
//------------------------------------------------------------------------------
class Location
{
public:
    GenTree* tree;
    BasicBlock* block;

    Location() : tree(nullptr), block(nullptr) {}

    Location(GenTree* t, BasicBlock* b) : tree(t), block(b)
    {
        DBEXEC(TRUE, Validate());
    }

    // construct a location consisting of the first tree after the start of the given block
    // (and the corresponding block, which may not be the same as the one passed in)
    Location(BasicBlock* b) : tree(nullptr), block(b)
    {
        Initialize();
    }

#ifdef DEBUG
    // Validate - basic validation that this (tree, block) tuple forms a real location
    void Validate()
    {
        if (tree != nullptr)
        {
            assert(Compiler::fgBlockContainsStatementBounded(block, tree));
            assert(tree->gtOper == GT_STMT);
        }
    }
#endif // DEBUG

    // Next - skip to next location,
    //        which means next tree in block, or next block's first tree, or a null location
    Location Next()
    {
        tree = tree->gtNext;
        while (tree == nullptr)
        {
            block = block->bbNext;
            if (block == nullptr)
            {
                return Location();
            }
            tree = block->bbTreeList;
        }
        assert(tree != nullptr);
        assert(tree->gtOper == GT_STMT);
        return *this;
    }

    void Reset(Compiler* comp)
    {
        block = comp->fgFirstBB;
        tree = nullptr;
        Initialize();
    }

private:
    void Initialize()
    {
        assert(tree == nullptr);
        tree = block->bbTreeList;
        while (tree == nullptr)
        {
            block = block->bbNext;
            if (block == nullptr)
            {
                block = nullptr;
                tree = nullptr;
                break;
            }
            tree = block->bbTreeList;
        }
        DBEXEC(TRUE, Validate());
    }
};

class Rationalizer : public Phase
{
    //===============================================================================
    // Data members

#ifdef DEBUG
    // keep track of whether a split happened so we can avoid expensive debug checks
    bool didSplit;
#endif

    // used for renaming updated variables
    hashBv *use;
    hashBv *usedef;
    hashBv *rename;
    hashBv *unexp;


    //===============================================================================
    // Methods
public:
    Rationalizer(Compiler* comp);
    Location TreeSplitRationalization     (Location loc);
    Location TreeTransformRationalization (Location loc);

    void RenameUpdatedVars(Location loc);

#ifdef DEBUG

    static void ValidateStatement(Location loc);
    static void ValidateStatement(GenTree* tree, BasicBlock* block);

    // general purpose sanity checking of de facto standard GenTree
    void SanityCheck(); 

    // sanity checking of rationalized IR
    void SanityCheckRational(); 

#endif // DEBUG

    virtual void DoPhase();
    typedef      ArrayStack<GenTree*> GenTreeStack;
    static void  MorphAsgIntoStoreLcl (GenTreeStmt* stmt, GenTreePtr pTree);

private:
    static Compiler::fgWalkResult CommaHelper          (GenTree** ppTree, Compiler::fgWalkData* data);
    static void                   RewriteOneComma      (GenTree** ppTree, Compiler::fgWalkData* data);
    static bool                   CommaUselessChild    (GenTree** ppTree, Compiler::fgWalkData* data);
    static void                   RecursiveRewriteComma(GenTree** ppTree, Compiler::fgWalkData* data, bool discard, bool nested);
    static bool                   RewriteArrElem       (GenTree** ppTree, Compiler::fgWalkData* data);

    static Compiler::fgWalkResult SimpleTransformHelper(GenTree** ppTree, Compiler::fgWalkData* data);
    static Compiler::fgWalkResult QuestionHelper       (GenTree** ppTree, Compiler::fgWalkData* data);

    static void       DuplicateCommaProcessOneTree (Compiler* comp, Rationalizer* irt, BasicBlock* block, GenTree* tree);

    static void       FixupIfCallArg               (GenTreeStack* parentStack,
                                                    GenTree* oldChild, 
                                                    GenTree* newChild);

    static void       FixupIfSIMDLocal             (Compiler* comp, GenTreeLclVarCommon* tree);

    static GenTreePtr CreateTempAssignment         (Compiler* comp,
                                                    unsigned lclNum,
                                                    GenTreePtr rhs);

    // Question related
    Location   RewriteQuestions         (Location loc);
    void       RewriteTopLevelComma     (Location loc, Location* out1, Location* out2);
    Location   RewriteSimpleTransforms  (Location loc);
    Location   RewriteOneQuestion       (BasicBlock* block, GenTree* op, GenTree* stmt, GenTree* dest);
    void       RewriteQuestions         (BasicBlock* block, GenTree* stmt);
    bool       BreakFirstLevelQuestions (BasicBlock* block, GenTree* tree);
    
    // SIMD related transformations
    static void RewriteLdObj(GenTreePtr* ppTree, Compiler::fgWalkData* data);
    static void RewriteCopyBlk(GenTreePtr* ppTree, Compiler::fgWalkData* data);
    static void RewriteInitBlk(GenTreePtr* ppTree, Compiler::fgWalkData* data);
};

inline Rationalizer::Rationalizer(Compiler* _comp)
                    : Phase(_comp, "IR Rationalize", PHASE_RATIONALIZE)
{
#ifdef DEBUG
    comp->compNumStatementLinksTraversed = 0;
#endif
}