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.
12template <typename T, int N>
13class 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
32public:
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
56struct 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".
70struct 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
80struct 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
129private:
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