summaryrefslogtreecommitdiff
path: root/src/jit/rationalize.h
blob: e1e7df140cc092ad994a612508751dc77f6fc46e (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
// 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.

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

//------------------------------------------------------------------------------
// 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
{
    //===============================================================================
    // Methods
public:
    Rationalizer(Compiler* comp);
    Location TreeTransformRationalization (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 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);

    Location RewriteTopLevelComma(Location loc);

    // SIMD related transformations
    static void RewriteObj(GenTreePtr* ppTree, Compiler::fgWalkData* data);
    static void RewriteCopyBlk(GenTreePtr* ppTree, Compiler::fgWalkData* data);
    static void RewriteInitBlk(GenTreePtr* ppTree, Compiler::fgWalkData* data);

    // Intrinsic related
    static void RewriteNodeAsCall(GenTreePtr* ppTree, Compiler::fgWalkData* data,
        CORINFO_METHOD_HANDLE callHnd,
#ifdef FEATURE_READYTORUN_COMPILER
        CORINFO_CONST_LOOKUP entryPoint,
#endif
        GenTreeArgList* args);
    static void RewriteIntrinsicAsUserCall(GenTreePtr* ppTree, Compiler::fgWalkData* data);
};

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