Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / stacklevelsetter.cpp
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 #include "jitpch.h"
6 #ifdef _MSC_VER
7 #pragma hdrstop
8 #endif
9
10 #ifndef LEGACY_BACKEND // This file is ONLY used for the RyuJIT backend that uses the linear scan register allocator
11
12 #include "stacklevelsetter.h"
13
14 StackLevelSetter::StackLevelSetter(Compiler* compiler)
15     : Phase(compiler, "StackLevelSetter", PHASE_STACK_LEVEL_SETTER)
16     , currentStackLevel(0)
17     , maxStackLevel(0)
18     , memAllocator(compiler, CMK_fgArgInfoPtrArr)
19     , putArgNumSlots(&memAllocator)
20 #if !FEATURE_FIXED_OUT_ARGS
21     , framePointerRequired(compiler->codeGen->isFramePointerRequired())
22     , throwHelperBlocksUsed(comp->fgUseThrowHelperBlocks() && comp->compUsesThrowHelper)
23 #endif // !FEATURE_FIXED_OUT_ARGS
24 {
25 }
26
27 //------------------------------------------------------------------------
28 // DoPhase: Calculate stack slots numbers for outgoing args.
29 //
30 // Notes:
31 //   For non-x86 platforms it calculates the max number of slots
32 //   that calls inside this method can push on the stack.
33 //   This value is used for sanity checks in the emitter.
34 //
35 //   Stack slots are pointer-sized: 4 bytes for 32-bit platforms, 8 bytes for 64-bit platforms.
36 //
37 //   For x86 it also sets throw-helper blocks incoming stack depth and set
38 //   framePointerRequired when it is necessary. These values are used to pop
39 //   pushed args when an exception occurs.
40 void StackLevelSetter::DoPhase()
41 {
42     for (BasicBlock* block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
43     {
44         ProcessBlock(block);
45     }
46 #if !FEATURE_FIXED_OUT_ARGS
47
48     if (framePointerRequired && !comp->codeGen->isFramePointerRequired())
49     {
50         JITDUMP("framePointerRequired is not set when it is required\n");
51         comp->codeGen->resetWritePhaseForFramePointerRequired();
52         comp->codeGen->setFramePointerRequired(true);
53     }
54 #endif // !FEATURE_FIXED_OUT_ARGS
55     if (maxStackLevel != comp->fgGetPtrArgCntMax())
56     {
57         JITDUMP("fgPtrArgCntMax was calculated wrong during the morph, the old value: %u, the right value: %u.\n",
58                 comp->fgGetPtrArgCntMax(), maxStackLevel);
59         comp->fgSetPtrArgCntMax(maxStackLevel);
60     }
61 }
62
63 //------------------------------------------------------------------------
64 // ProcessBlock: Do stack level calculations for one block.
65 //
66 // Notes:
67 //   Block starts and ends with an empty outgoing stack.
68 //   Nodes in blocks are iterated in the reverse order to memorize GT_PUTARG_STK
69 //   and GT_PUTARG_SPLIT stack sizes.
70 //
71 // Arguments:
72 //   block - the block to process.
73 //
74 void StackLevelSetter::ProcessBlock(BasicBlock* block)
75 {
76     assert(currentStackLevel == 0);
77     LIR::ReadOnlyRange& range = LIR::AsRange(block);
78     for (auto i = range.rbegin(); i != range.rend(); ++i)
79     {
80         GenTree* node = *i;
81         if (node->OperIsPutArgStkOrSplit())
82         {
83             GenTreePutArgStk* putArg   = node->AsPutArgStk();
84             unsigned          numSlots = putArgNumSlots[putArg];
85             putArgNumSlots.Remove(putArg);
86             SubStackLevel(numSlots);
87         }
88
89 #if !FEATURE_FIXED_OUT_ARGS
90         // Set throw blocks incoming stack depth for x86.
91         if (throwHelperBlocksUsed && !framePointerRequired)
92         {
93             if (node->OperMayThrow(comp))
94             {
95                 SetThrowHelperBlocks(node, block);
96             }
97         }
98 #endif // !FEATURE_FIXED_OUT_ARGS
99
100         if (node->IsCall())
101         {
102             GenTreeCall* call = node->AsCall();
103
104             unsigned usedStackSlotsCount = PopArgumentsFromCall(call);
105 #if defined(UNIX_X86_ABI)
106             assert(call->fgArgInfo->GetStkSizeBytes() == usedStackSlotsCount * TARGET_POINTER_SIZE);
107             call->fgArgInfo->SetStkSizeBytes(usedStackSlotsCount * TARGET_POINTER_SIZE);
108 #endif // UNIX_X86_ABI
109         }
110     }
111     assert(currentStackLevel == 0);
112 }
113
114 #if !FEATURE_FIXED_OUT_ARGS
115 //------------------------------------------------------------------------
116 // SetThrowHelperBlocks: Set throw helper blocks incoming stack levels targeted
117 //                       from the node.
118 //
119 // Notes:
120 //   one node can target several helper blocks, but not all operands that throw do this.
121 //   So the function can set 0-2 throw blocks depends on oper and overflow flag.
122 //
123 // Arguments:
124 //   node - the node to process;
125 //   block - the source block for the node.
126 void StackLevelSetter::SetThrowHelperBlocks(GenTree* node, BasicBlock* block)
127 {
128     assert(node->OperMayThrow(comp));
129
130     // Check that it uses throw block, find its kind, find the block, set level.
131     switch (node->OperGet())
132     {
133         case GT_ARR_BOUNDS_CHECK:
134 #ifdef FEATURE_SIMD
135         case GT_SIMD_CHK:
136 #endif // FEATURE_SIMD
137 #ifdef FEATURE_HW_INTRINSICS
138         case GT_HW_INTRINSIC_CHK:
139 #endif // FEATURE_HW_INTRINSICS
140         {
141             GenTreeBoundsChk* bndsChk = node->AsBoundsChk();
142             SetThrowHelperBlock(bndsChk->gtThrowKind, block);
143         }
144         break;
145         case GT_INDEX_ADDR:
146         case GT_ARR_ELEM:
147         case GT_ARR_INDEX:
148         {
149             SetThrowHelperBlock(SCK_RNGCHK_FAIL, block);
150         }
151         break;
152
153         case GT_CKFINITE:
154         {
155             SetThrowHelperBlock(SCK_ARITH_EXCPN, block);
156         }
157         break;
158         default: // Other opers can target throw only due to overflow.
159             break;
160     }
161     if (node->gtOverflowEx())
162     {
163         SetThrowHelperBlock(SCK_OVERFLOW, block);
164     }
165 }
166
167 //------------------------------------------------------------------------
168 // SetThrowHelperBlock: Set throw helper block incoming stack levels targeted
169 //                      from the block with this kind.
170 //
171 // Notes:
172 //   Set framePointerRequired if finds that the block has several incoming edges
173 //   with different stack levels.
174 //
175 // Arguments:
176 //   kind - the special throw-helper kind;
177 //   block - the source block that targets helper.
178 void StackLevelSetter::SetThrowHelperBlock(SpecialCodeKind kind, BasicBlock* block)
179 {
180     Compiler::AddCodeDsc* add = comp->fgFindExcptnTarget(kind, comp->bbThrowIndex(block));
181     assert(add != nullptr);
182     if (add->acdStkLvlInit)
183     {
184         if (add->acdStkLvl != currentStackLevel)
185         {
186             framePointerRequired = true;
187         }
188     }
189     else
190     {
191         add->acdStkLvlInit = true;
192         if (add->acdStkLvl != currentStackLevel)
193         {
194             JITDUMP("Wrong stack level was set for block %d\n", add->acdDstBlk->bbNum);
195         }
196 #ifdef DEBUG
197         add->acdDstBlk->bbTgtStkDepth = currentStackLevel;
198 #endif // Debug
199         add->acdStkLvl = currentStackLevel;
200     }
201 }
202
203 #endif // !FEATURE_FIXED_OUT_ARGS
204
205 //------------------------------------------------------------------------
206 // PopArgumentsFromCall: Calculate the number of stack arguments that are used by the call.
207 //
208 // Notes:
209 //   memorize number of slots that each stack argument use.
210 //
211 // Arguments:
212 //   call - the call to process.
213 //
214 // Return value:
215 //   the number of stack slots in stack arguments for the call.
216 unsigned StackLevelSetter::PopArgumentsFromCall(GenTreeCall* call)
217 {
218     unsigned   usedStackSlotsCount = 0;
219     fgArgInfo* argInfo             = call->fgArgInfo;
220     if (argInfo->HasStackArgs())
221     {
222         for (unsigned i = 0; i < argInfo->ArgCount(); ++i)
223         {
224             fgArgTabEntry* argTab = argInfo->ArgTable()[i];
225             if (argTab->numSlots != 0)
226             {
227                 GenTree* node = argTab->node;
228                 assert(node->OperIsPutArgStkOrSplit());
229
230                 GenTreePutArgStk* putArg = node->AsPutArgStk();
231
232 #if !FEATURE_FIXED_OUT_ARGS
233                 assert(argTab->numSlots == putArg->gtNumSlots);
234 #endif // !FEATURE_FIXED_OUT_ARGS
235
236                 putArgNumSlots.Set(putArg, argTab->numSlots);
237
238                 usedStackSlotsCount += argTab->numSlots;
239                 AddStackLevel(argTab->numSlots);
240             }
241         }
242     }
243     return usedStackSlotsCount;
244 }
245
246 //------------------------------------------------------------------------
247 // SubStackLevel: Reflect pushing to the stack.
248 //
249 // Arguments:
250 //   value - a positive value to add.
251 //
252 void StackLevelSetter::AddStackLevel(unsigned value)
253 {
254     currentStackLevel += value;
255
256     if (currentStackLevel > maxStackLevel)
257     {
258         maxStackLevel = currentStackLevel;
259     }
260 }
261
262 //------------------------------------------------------------------------
263 // SubStackLevel: Reflect popping from the stack.
264 //
265 // Arguments:
266 //   value - a positive value to subtract.
267 //
268 void StackLevelSetter::SubStackLevel(unsigned value)
269 {
270     assert(currentStackLevel >= value);
271     currentStackLevel -= value;
272 }
273
274 #endif // !LEGACY_BACKEND