Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / sharedfloat.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 //
6 // NOTE: The code in this file is only used for LEGACY_BACKEND compiles.
7
8 #include "jitpch.h"
9 #ifdef _MSC_VER
10 #pragma hdrstop
11 #endif
12
13 #include "compiler.h"
14 #include "emit.h"
15 #include "codegen.h"
16
17 #ifdef LEGACY_BACKEND
18
19 #if FEATURE_STACK_FP_X87
20 regMaskTP RegSet::rsGetMaskUsed()
21 {
22     return rsMaskUsedFloat;
23 }
24 regMaskTP RegSet::rsGetMaskVars()
25 {
26     return rsMaskRegVarFloat;
27 }
28 regMaskTP RegSet::rsGetMaskLock()
29 {
30     return rsMaskLockedFloat;
31 }
32 regMaskTP RegSet::rsGetMaskMult()
33 {
34     return 0;
35 }
36
37 void RegSet::rsSetMaskUsed(regMaskTP maskUsed)
38 {
39     rsMaskUsedFloat = maskUsed;
40 }
41 void RegSet::rsSetMaskVars(regMaskTP maskVars)
42 {
43     rsMaskRegVarFloat = maskVars;
44 }
45 void RegSet::rsSetMaskLock(regMaskTP maskLock)
46 {
47     rsMaskLockedFloat = maskLock;
48 }
49
50 void RegSet::rsSetUsedTree(regNumber regNum, GenTree* tree)
51 {
52     assert(genUsedRegsFloat[regNum] == 0);
53     genUsedRegsFloat[regNum] = tree;
54 }
55 void RegSet::rsFreeUsedTree(regNumber regNum, GenTree* tree)
56 {
57     assert(genUsedRegsFloat[regNum] == tree);
58     genUsedRegsFloat[regNum] = 0;
59 }
60
61 #else  // !FEATURE_STACK_FP_X87
62 regMaskTP RegSet::rsGetMaskUsed()
63 {
64     return rsMaskUsed;
65 }
66 regMaskTP RegSet::rsGetMaskVars()
67 {
68     return rsMaskVars;
69 }
70 regMaskTP RegSet::rsGetMaskLock()
71 {
72     return rsMaskLock;
73 }
74 regMaskTP RegSet::rsGetMaskMult()
75 {
76     return rsMaskMult;
77 }
78
79 void RegSet::rsSetMaskUsed(regMaskTP maskUsed)
80 {
81     rsMaskUsed = maskUsed;
82 }
83 void RegSet::rsSetMaskVars(regMaskTP maskVars)
84 {
85     rsMaskVars = maskVars;
86 }
87 void RegSet::rsSetMaskLock(regMaskTP maskLock)
88 {
89     rsMaskLock = maskLock;
90 }
91
92 void RegSet::rsSetUsedTree(regNumber regNum, GenTree* tree)
93 {
94     assert(rsUsedTree[regNum] == 0);
95     rsUsedTree[regNum] = tree;
96 }
97 void RegSet::rsFreeUsedTree(regNumber regNum, GenTree* tree)
98 {
99     assert(rsUsedTree[regNum] == tree);
100     rsUsedTree[regNum] = 0;
101 }
102 #endif // !FEATURE_STACK_FP_X87
103
104 // float stress mode. Will lock out registers to stress high register pressure.
105 // This implies setting interferences in register allocator and pushing regs in
106 // the prolog and popping them before a ret.
107 #ifdef DEBUG
108 int CodeGenInterface::genStressFloat()
109 {
110     return compiler->compStressCompile(Compiler::STRESS_FLATFP, 40) ? 1 : JitConfig.JitStressFP();
111 }
112 #endif
113
114 regMaskTP RegSet::RegFreeFloat()
115 {
116     regMaskTP mask = RBM_ALLFLOAT;
117 #if FEATURE_FP_REGALLOC
118     mask &= m_rsCompiler->raConfigRestrictMaskFP();
119 #endif
120
121     mask &= ~rsGetMaskUsed();
122     mask &= ~rsGetMaskLock();
123     mask &= ~rsGetMaskVars();
124
125 #ifdef DEBUG
126     if (m_rsCompiler->codeGen->genStressFloat())
127     {
128         mask &= ~(m_rsCompiler->codeGen->genStressLockedMaskFloat());
129     }
130 #endif
131     return mask;
132 }
133
134 #ifdef _TARGET_ARM_
135 // order registers are picked
136 // go in reverse order to minimize chance of spilling with calls
137 static const regNumber pickOrder[] = {REG_F15, REG_F14, REG_F13, REG_F12, REG_F11, REG_F10, REG_F9,  REG_F8,
138                                       REG_F7,  REG_F6,  REG_F5,  REG_F4,  REG_F3,  REG_F2,  REG_F1,  REG_F0,
139
140                                       REG_F16, REG_F17, REG_F18, REG_F19, REG_F20, REG_F21, REG_F22, REG_F23,
141                                       REG_F24, REG_F25, REG_F26, REG_F27, REG_F28, REG_F29, REG_F30, REG_F31};
142
143 #elif _TARGET_AMD64_
144 // order registers are picked
145 static const regNumber pickOrder[] = {REG_XMM0,  REG_XMM1,  REG_XMM2,  REG_XMM3, REG_XMM4,  REG_XMM5,
146                                       REG_XMM6,  REG_XMM7,  REG_XMM8,  REG_XMM9, REG_XMM10, REG_XMM11,
147                                       REG_XMM12, REG_XMM13, REG_XMM14, REG_XMM15};
148
149 #elif _TARGET_X86_
150 // order registers are picked
151 static const regNumber pickOrder[] = {REG_FPV0, REG_FPV1, REG_FPV2, REG_FPV3, REG_FPV4, REG_FPV5, REG_FPV6, REG_FPV7};
152 #endif
153
154 // picks a reg other than the one specified
155 regNumber RegSet::PickRegFloatOtherThan(GenTree* tree, var_types type, regNumber reg)
156 {
157     return PickRegFloatOtherThan(type, reg);
158 }
159
160 regNumber RegSet::PickRegFloatOtherThan(var_types type, regNumber reg)
161 {
162     RegisterPreference pref(RBM_ALLFLOAT ^ genRegMask(reg), 0);
163     return PickRegFloat(type, &pref);
164 }
165
166 regNumber RegSet::PickRegFloat(GenTree* tree, var_types type, RegisterPreference* pref, bool bUsed)
167 {
168     return PickRegFloat(type, pref, bUsed);
169 }
170
171 regNumber RegSet::PickRegFloat(var_types type, RegisterPreference* pref, bool bUsed)
172 {
173     regMaskTP wantedMask;
174     bool      tryBest = true;
175     bool      tryOk   = true;
176     bool      bSpill  = false;
177     regNumber reg     = REG_NA;
178
179     while (tryOk)
180     {
181         if (pref)
182         {
183             if (tryBest)
184             {
185                 wantedMask = pref->best;
186                 tryBest    = false;
187             }
188             else
189             {
190                 assert(tryOk);
191                 wantedMask = pref->ok;
192                 tryOk      = false;
193             }
194         }
195         else // pref is NULL
196         {
197             wantedMask = RBM_ALLFLOAT;
198             tryBest    = false;
199             tryOk      = false;
200         }
201
202         // better not have asked for a non-fp register
203         assert((wantedMask & ~RBM_ALLFLOAT) == 0);
204
205         regMaskTP availMask = RegFreeFloat();
206         regMaskTP OKmask    = availMask & wantedMask;
207
208         if (OKmask == 0)
209         {
210             if (tryOk)
211             {
212                 // the pref->best mask doesn't work so try the pref->ok mask next
213                 continue;
214             }
215
216             if (bUsed)
217             {
218                 // Allow used registers to be picked
219                 OKmask |= rsGetMaskUsed() & ~rsGetMaskLock();
220                 bSpill = true;
221             }
222         }
223 #if FEATURE_FP_REGALLOC
224         regMaskTP restrictMask = (m_rsCompiler->raConfigRestrictMaskFP() | RBM_FLT_CALLEE_TRASH);
225 #endif
226
227         for (unsigned i = 0; i < ArrLen(pickOrder); i++)
228         {
229             regNumber r = pickOrder[i];
230             if (!floatRegCanHoldType(r, type))
231                 continue;
232
233             regMaskTP mask = genRegMaskFloat(r, type);
234
235 #if FEATURE_FP_REGALLOC
236             if ((mask & restrictMask) != mask)
237                 continue;
238 #endif
239             if ((OKmask & mask) == mask)
240             {
241                 reg = r;
242                 goto RET;
243             }
244         }
245
246         if (tryOk)
247         {
248             // We couldn't find a register using tryBest
249             continue;
250         }
251
252         assert(!"Unable to find a free FP virtual register");
253         NO_WAY("FP register allocator was too optimistic!");
254     }
255 RET:
256     if (bSpill)
257     {
258         m_rsCompiler->codeGen->SpillFloat(reg);
259     }
260
261 #if FEATURE_FP_REGALLOC
262     rsSetRegsModified(genRegMaskFloat(reg, type));
263 #endif
264
265     return reg;
266 }
267
268 #ifdef LEGACY_BACKEND
269 void RegSet::SetUsedRegFloat(GenTree* tree, bool bValue)
270 {
271     /* The value must be sitting in a register */
272     assert(tree);
273     assert(tree->InReg());
274
275     var_types type = tree->TypeGet();
276 #ifdef _TARGET_ARM_
277     if (type == TYP_STRUCT)
278     {
279         assert(m_rsCompiler->IsHfa(tree));
280         type = TYP_FLOAT;
281     }
282 #endif
283     regNumber regNum  = tree->gtRegNum;
284     regMaskTP regMask = genRegMaskFloat(regNum, type);
285
286     if (bValue)
287     {
288 #ifdef DEBUG
289         if (m_rsCompiler->verbose)
290         {
291             printf("\t\t\t\t\t\t\tThe register %s currently holds ", getRegNameFloat(regNum, type));
292             Compiler::printTreeID(tree);
293             printf("\n");
294         }
295 #endif
296
297         // Mark as used
298         assert((rsGetMaskLock() & regMask) == 0);
299
300 #if FEATURE_STACK_FP_X87
301         assert((rsGetMaskUsed() & regMask) == 0);
302 #else
303         /* Is the register used by two different values simultaneously? */
304
305         if (regMask & rsGetMaskUsed())
306         {
307             /* Save the preceding use information */
308
309             rsRecMultiReg(regNum, type);
310         }
311 #endif
312         /* Set the register's bit in the 'used' bitset */
313
314         rsSetMaskUsed((rsGetMaskUsed() | regMask));
315
316         // Assign slot
317         rsSetUsedTree(regNum, tree);
318     }
319     else
320     {
321 #ifdef DEBUG
322         if (m_rsCompiler->verbose)
323         {
324             printf("\t\t\t\t\t\t\tThe register %s no longer holds ", getRegNameFloat(regNum, type));
325             Compiler::printTreeID(tree);
326             printf("\n");
327         }
328 #endif
329
330         // Mark as free
331         assert((rsGetMaskUsed() & regMask) == regMask);
332
333         // Are we freeing a multi-use registers?
334
335         if (regMask & rsGetMaskMult())
336         {
337             // Free any multi-use registers
338             rsMultRegFree(regMask);
339             return;
340         }
341
342         rsSetMaskUsed((rsGetMaskUsed() & ~regMask));
343
344         // Free slot
345         rsFreeUsedTree(regNum, tree);
346     }
347 }
348 #endif // LEGACY_BACKEND
349
350 void RegSet::SetLockedRegFloat(GenTree* tree, bool bValue)
351 {
352     regNumber reg  = tree->gtRegNum;
353     var_types type = tree->TypeGet();
354     assert(varTypeIsFloating(type));
355     regMaskTP regMask = genRegMaskFloat(reg, tree->TypeGet());
356
357     if (bValue)
358     {
359         JITDUMP("locking register %s\n", getRegNameFloat(reg, type));
360
361         assert((rsGetMaskUsed() & regMask) == regMask);
362         assert((rsGetMaskLock() & regMask) == 0);
363
364         rsSetMaskLock((rsGetMaskLock() | regMask));
365     }
366     else
367     {
368         JITDUMP("unlocking register %s\n", getRegNameFloat(reg, type));
369
370         assert((rsGetMaskUsed() & regMask) == regMask);
371         assert((rsGetMaskLock() & regMask) == regMask);
372
373         rsSetMaskLock((rsGetMaskLock() & ~regMask));
374     }
375 }
376
377 bool RegSet::IsLockedRegFloat(GenTree* tree)
378 {
379     /* The value must be sitting in a register */
380     assert(tree);
381     assert(tree->InReg());
382     assert(varTypeIsFloating(tree->TypeGet()));
383
384     regMaskTP regMask = genRegMaskFloat(tree->gtRegNum, tree->TypeGet());
385     return (rsGetMaskLock() & regMask) == regMask;
386 }
387
388 void CodeGen::UnspillFloat(GenTree* tree)
389 {
390 #ifdef DEBUG
391     if (verbose)
392     {
393         printf("UnspillFloat() for tree ");
394         Compiler::printTreeID(tree);
395         printf("\n");
396     }
397 #endif // DEBUG
398
399     RegSet::SpillDsc* cur = regSet.rsSpillFloat;
400     assert(cur);
401
402     while (cur->spillTree != tree)
403         cur = cur->spillNext;
404
405     UnspillFloat(cur);
406 }
407
408 void CodeGen::UnspillFloat(LclVarDsc* varDsc)
409 {
410     JITDUMP("UnspillFloat() for var [%08p]\n", dspPtr(varDsc));
411
412     RegSet::SpillDsc* cur = regSet.rsSpillFloat;
413     assert(cur);
414
415     while (cur->spillVarDsc != varDsc)
416         cur = cur->spillNext;
417
418     UnspillFloat(cur);
419 }
420
421 void CodeGen::RemoveSpillDsc(RegSet::SpillDsc* spillDsc)
422 {
423     RegSet::SpillDsc*  cur;
424     RegSet::SpillDsc** prev;
425
426     for (cur = regSet.rsSpillFloat, prev = &regSet.rsSpillFloat; cur != spillDsc;
427          prev = &cur->spillNext, cur = cur->spillNext)
428         ; // EMPTY LOOP
429
430     assert(cur);
431
432     // Remove node from list
433     *prev = cur->spillNext;
434 }
435
436 void CodeGen::UnspillFloat(RegSet::SpillDsc* spillDsc)
437 {
438     JITDUMP("UnspillFloat() for SpillDsc [%08p]\n", dspPtr(spillDsc));
439
440     RemoveSpillDsc(spillDsc);
441     UnspillFloatMachineDep(spillDsc);
442
443     RegSet::SpillDsc::freeDsc(&regSet, spillDsc);
444     compiler->tmpRlsTemp(spillDsc->spillTemp);
445 }
446
447 #if FEATURE_STACK_FP_X87
448
449 Compiler::fgWalkResult CodeGen::genRegVarDiesInSubTreeWorker(GenTree** pTree, Compiler::fgWalkData* data)
450 {
451     GenTree*                    tree  = *pTree;
452     genRegVarDiesInSubTreeData* pData = (genRegVarDiesInSubTreeData*)data->pCallbackData;
453
454     // if it's dying, just rename the register, else load it normally
455     if (tree->IsRegVar() && tree->IsRegVarDeath() && tree->gtRegVar.gtRegNum == pData->reg)
456     {
457         pData->result = true;
458         return Compiler::WALK_ABORT;
459     }
460
461     return Compiler::WALK_CONTINUE;
462 }
463
464 bool CodeGen::genRegVarDiesInSubTree(GenTree* tree, regNumber reg)
465 {
466     genRegVarDiesInSubTreeData Data;
467     Data.reg    = reg;
468     Data.result = false;
469
470     compiler->fgWalkTreePre(&tree, genRegVarDiesInSubTreeWorker, (void*)&Data);
471
472     return Data.result;
473 }
474
475 #endif // FEATURE_STACK_FP_X87
476
477 /*****************************************************************************
478  *
479  *  Force floating point expression results to memory, to get rid of the extra
480  *  80 byte "temp-real" precision.
481  *  Assumes the tree operand has been computed to the top of the stack.
482  *  If type!=TYP_UNDEF, that is the desired presicion, else it is op->gtType
483  */
484
485 void CodeGen::genRoundFpExpression(GenTree* op, var_types type)
486 {
487 #if FEATURE_STACK_FP_X87
488     return genRoundFpExpressionStackFP(op, type);
489 #else
490     return genRoundFloatExpression(op, type);
491 #endif
492 }
493
494 void CodeGen::genCodeForTreeFloat(GenTree* tree, regMaskTP needReg, regMaskTP bestReg)
495 {
496     RegSet::RegisterPreference pref(needReg, bestReg);
497     genCodeForTreeFloat(tree, &pref);
498 }
499
500 #endif // LEGACY_BACKEND