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 | #pragma once |
6 | |
7 | #include "jitstd.h" |
8 | |
9 | // Fixed-size array that can hold elements with no default constructor; |
10 | // it will construct them all by forwarding whatever arguments are |
11 | // supplied to its constructor. |
12 | template <typename T, int N> |
13 | class ConstructedArray |
14 | { |
15 | union { |
16 | // Storage that gets used to hold the T objects. |
17 | unsigned char bytes[N * sizeof(T)]; |
18 | |
19 | #if defined(_MSC_VER) && (_MSC_VER < 1900) |
20 | // With MSVC pre-VS2015, the code in the #else branch would hit error C2621, |
21 | // so in that case just count on pointer alignment being sufficient |
22 | // (currently T is only ever instantiated as jitstd::list<SsaRenameStateForBlock>) |
23 | |
24 | // Unused (except to impart alignment requirement) |
25 | void* pointer; |
26 | #else |
27 | // Unused (except to impart alignment requirement) |
28 | T alignedArray[N]; |
29 | #endif // defined(_MSC_VER) && (_MSC_VER < 1900) |
30 | }; |
31 | |
32 | public: |
33 | T& operator[](size_t i) |
34 | { |
35 | return *(reinterpret_cast<T*>(bytes + i * sizeof(T))); |
36 | } |
37 | |
38 | template <typename... Args> |
39 | ConstructedArray(Args&&... args) |
40 | { |
41 | for (int i = 0; i < N; ++i) |
42 | { |
43 | new (bytes + i * sizeof(T), jitstd::placement_t()) T(jitstd::forward<Args>(args)...); |
44 | } |
45 | } |
46 | |
47 | ~ConstructedArray() |
48 | { |
49 | for (int i = 0; i < N; ++i) |
50 | { |
51 | operator[](i).~T(); |
52 | } |
53 | } |
54 | }; |
55 | |
56 | struct SsaRenameStateForBlock |
57 | { |
58 | BasicBlock* m_bb; |
59 | unsigned m_count; |
60 | |
61 | SsaRenameStateForBlock(BasicBlock* bb, unsigned count) : m_bb(bb), m_count(count) |
62 | { |
63 | } |
64 | SsaRenameStateForBlock() : m_bb(nullptr), m_count(0) |
65 | { |
66 | } |
67 | }; |
68 | |
69 | // A record indicating that local "m_loc" was defined in block "m_bb". |
70 | struct SsaRenameStateLocDef |
71 | { |
72 | BasicBlock* m_bb; |
73 | unsigned m_lclNum; |
74 | |
75 | SsaRenameStateLocDef(BasicBlock* bb, unsigned lclNum) : m_bb(bb), m_lclNum(lclNum) |
76 | { |
77 | } |
78 | }; |
79 | |
80 | struct SsaRenameState |
81 | { |
82 | typedef jitstd::list<SsaRenameStateForBlock> Stack; |
83 | typedef Stack** Stacks; |
84 | typedef jitstd::list<SsaRenameStateLocDef> DefStack; |
85 | |
86 | SsaRenameState(CompAllocator allocator, unsigned lvaCount, bool byrefStatesMatchGcHeapStates); |
87 | |
88 | void EnsureStacks(); |
89 | |
90 | // Requires "lclNum" to be a variable number for which an ssa number at the top of the |
91 | // stack is required i.e., for variable "uses." |
92 | unsigned CountForUse(unsigned lclNum); |
93 | |
94 | // Requires "lclNum" to be a variable number, and requires "count" to represent |
95 | // an ssa number, that needs to be pushed on to the stack corresponding to the lclNum. |
96 | void Push(BasicBlock* bb, unsigned lclNum, unsigned count); |
97 | |
98 | // Pop all stacks that have an entry for "bb" on top. |
99 | void PopBlockStacks(BasicBlock* bb); |
100 | |
101 | // Similar functions for the special implicit memory variable. |
102 | unsigned CountForMemoryUse(MemoryKind memoryKind) |
103 | { |
104 | if ((memoryKind == GcHeap) && byrefStatesMatchGcHeapStates) |
105 | { |
106 | // Share rename stacks in this configuration. |
107 | memoryKind = ByrefExposed; |
108 | } |
109 | return memoryStack[memoryKind].back().m_count; |
110 | } |
111 | |
112 | void PushMemory(MemoryKind memoryKind, BasicBlock* bb, unsigned count) |
113 | { |
114 | if ((memoryKind == GcHeap) && byrefStatesMatchGcHeapStates) |
115 | { |
116 | // Share rename stacks in this configuration. |
117 | memoryKind = ByrefExposed; |
118 | } |
119 | memoryStack[memoryKind].push_back(SsaRenameStateForBlock(bb, count)); |
120 | } |
121 | |
122 | void PopBlockMemoryStack(MemoryKind memoryKind, BasicBlock* bb); |
123 | |
124 | #ifdef DEBUG |
125 | // Debug interface |
126 | void DumpStacks(); |
127 | #endif |
128 | |
129 | private: |
130 | // Map of lclNum -> SsaRenameStateForBlock. |
131 | Stacks stacks; |
132 | |
133 | // This list represents the set of locals defined in the current block. |
134 | DefStack definedLocs; |
135 | |
136 | // Same state for the special implicit memory variables. |
137 | ConstructedArray<Stack, MemoryKindCount> memoryStack; |
138 | |
139 | // Number of stacks/counts to allocate. |
140 | unsigned lvaCount; |
141 | |
142 | // Allocator to allocate stacks. |
143 | CompAllocator m_alloc; |
144 | |
145 | // Indicates whether GcHeap and ByrefExposed use the same state. |
146 | bool byrefStatesMatchGcHeapStates; |
147 | }; |
148 | |