Sync may31 release/8.0-tizen (#510)
[platform/upstream/dotnet/runtime.git] / src / coreclr / jit / codegencommon.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
4 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XX                                                                           XX
7 XX Code Generator Common:                                                    XX
8 XX   Methods common to all architectures and register allocation strategies  XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13
14 // TODO-Cleanup: There are additional methods in CodeGen*.cpp that are almost
15 // identical, and which should probably be moved here.
16
17 #include "jitpch.h"
18 #ifdef _MSC_VER
19 #pragma hdrstop
20 #endif
21 #include "codegen.h"
22
23 #include "gcinfo.h"
24 #include "emit.h"
25
26 #ifndef JIT32_GCENCODER
27 #include "gcinfoencoder.h"
28 #endif
29
30 #include "patchpointinfo.h"
31
32 /*****************************************************************************/
33
34 void CodeGenInterface::setFramePointerRequiredEH(bool value)
35 {
36     m_cgFramePointerRequired = value;
37
38 #ifndef JIT32_GCENCODER
39     if (value)
40     {
41         // EnumGcRefs will only enumerate slots in aborted frames
42         // if they are fully-interruptible.  So if we have a catch
43         // or finally that will keep frame-vars alive, we need to
44         // force fully-interruptible.
45         CLANG_FORMAT_COMMENT_ANCHOR;
46
47 #ifdef DEBUG
48         if (verbose)
49         {
50             printf("Method has EH, marking method as fully interruptible\n");
51         }
52 #endif
53
54         m_cgInterruptible = true;
55     }
56 #endif // JIT32_GCENCODER
57 }
58
59 /*****************************************************************************/
60 CodeGenInterface* getCodeGenerator(Compiler* comp)
61 {
62     return new (comp, CMK_Codegen) CodeGen(comp);
63 }
64
65 // CodeGen constructor
66 CodeGenInterface::CodeGenInterface(Compiler* theCompiler)
67     : gcInfo(theCompiler), regSet(theCompiler, gcInfo), compiler(theCompiler), treeLifeUpdater(nullptr)
68 {
69 }
70
71 #if defined(TARGET_XARCH)
72 void CodeGenInterface::CopyRegisterInfo()
73 {
74 #if defined(TARGET_AMD64)
75     rbmAllFloat       = compiler->rbmAllFloat;
76     rbmFltCalleeTrash = compiler->rbmFltCalleeTrash;
77 #endif // TARGET_AMD64
78
79     rbmAllMask        = compiler->rbmAllMask;
80     rbmMskCalleeTrash = compiler->rbmMskCalleeTrash;
81 }
82 #endif // TARGET_XARCH
83
84 /*****************************************************************************/
85
86 CodeGen::CodeGen(Compiler* theCompiler) : CodeGenInterface(theCompiler)
87 {
88 #if defined(TARGET_XARCH)
89     negBitmaskFlt  = nullptr;
90     negBitmaskDbl  = nullptr;
91     absBitmaskFlt  = nullptr;
92     absBitmaskDbl  = nullptr;
93     zroSimd12Elm3  = nullptr;
94     u8ToDblBitmask = nullptr;
95 #endif // defined(TARGET_XARCH)
96
97 #if defined(FEATURE_PUT_STRUCT_ARG_STK) && !defined(TARGET_X86)
98     m_stkArgVarNum = BAD_VAR_NUM;
99 #endif
100
101 #if defined(UNIX_X86_ABI)
102     curNestedAlignment = 0;
103     maxNestedAlignment = 0;
104 #endif
105
106     gcInfo.regSet        = &regSet;
107     m_cgEmitter          = new (compiler->getAllocator()) emitter();
108     m_cgEmitter->codeGen = this;
109     m_cgEmitter->gcInfo  = &gcInfo;
110
111 #ifdef DEBUG
112     setVerbose(compiler->verbose);
113 #endif // DEBUG
114
115     regSet.tmpInit();
116
117 #ifdef LATE_DISASM
118     getDisAssembler().disInit(compiler);
119 #endif
120
121 #ifdef DEBUG
122     genTempLiveChg        = true;
123     genTrnslLocalVarCount = 0;
124
125     // Shouldn't be used before it is set in genFnProlog()
126     compiler->compCalleeRegsPushed = UninitializedWord<unsigned>(compiler);
127
128 #if defined(TARGET_XARCH)
129     // Shouldn't be used before it is set in genFnProlog()
130     compiler->compCalleeFPRegsSavedMask = (regMaskTP)-1;
131 #endif // defined(TARGET_XARCH)
132 #endif // DEBUG
133
134 #ifdef TARGET_AMD64
135     // This will be set before final frame layout.
136     compiler->compVSQuirkStackPaddingNeeded = 0;
137 #endif // TARGET_AMD64
138
139     compiler->genCallSite2DebugInfoMap = nullptr;
140
141     /* Assume that we not fully interruptible */
142
143     SetInterruptible(false);
144 #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
145     SetHasTailCalls(false);
146 #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64
147 #ifdef DEBUG
148     genInterruptibleUsed = false;
149     genCurDispOffset     = (unsigned)-1;
150 #endif
151
152 #ifdef TARGET_ARM64
153     genSaveFpLrWithAllCalleeSavedRegisters = false;
154     genForceFuncletFrameType5              = false;
155 #endif // TARGET_ARM64
156 }
157
158 #if defined(TARGET_X86) || defined(TARGET_ARM)
159
160 //---------------------------------------------------------------------
161 // genTotalFrameSize - return the "total" size of the stack frame, including local size
162 // and callee-saved register size. There are a few things "missing" depending on the
163 // platform. The function genCallerSPtoInitialSPdelta() includes those things.
164 //
165 // For ARM, this doesn't include the prespilled registers.
166 //
167 // For x86, this doesn't include the frame pointer if codeGen->isFramePointerUsed() is true.
168 // It also doesn't include the pushed return address.
169 //
170 // Return value:
171 //    Frame size
172
173 int CodeGenInterface::genTotalFrameSize() const
174 {
175     assert(!IsUninitialized(compiler->compCalleeRegsPushed));
176
177     int totalFrameSize = compiler->compCalleeRegsPushed * REGSIZE_BYTES + compiler->compLclFrameSize;
178
179     assert(totalFrameSize >= 0);
180     return totalFrameSize;
181 }
182
183 //---------------------------------------------------------------------
184 // genSPtoFPdelta - return the offset from SP to the frame pointer.
185 // This number is going to be positive, since SP must be at the lowest
186 // address.
187 //
188 // There must be a frame pointer to call this function!
189
190 int CodeGenInterface::genSPtoFPdelta() const
191 {
192     assert(isFramePointerUsed());
193
194     int delta;
195
196     delta = -genCallerSPtoInitialSPdelta() + genCallerSPtoFPdelta();
197
198     assert(delta >= 0);
199     return delta;
200 }
201
202 //---------------------------------------------------------------------
203 // genCallerSPtoFPdelta - return the offset from Caller-SP to the frame pointer.
204 // This number is going to be negative, since the Caller-SP is at a higher
205 // address than the frame pointer.
206 //
207 // There must be a frame pointer to call this function!
208
209 int CodeGenInterface::genCallerSPtoFPdelta() const
210 {
211     assert(isFramePointerUsed());
212     int callerSPtoFPdelta = 0;
213
214 #if defined(TARGET_ARM)
215     // On ARM, we first push the prespill registers, then store LR, then R11 (FP), and point R11 at the saved R11.
216     callerSPtoFPdelta -= genCountBits(regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
217     callerSPtoFPdelta -= 2 * REGSIZE_BYTES;
218 #elif defined(TARGET_X86)
219     // Thanks to ebp chaining, the difference between ebp-based addresses
220     // and caller-SP-relative addresses is just the 2 pointers:
221     //     return address
222     //     pushed ebp
223     callerSPtoFPdelta -= 2 * REGSIZE_BYTES;
224 #else
225 #error "Unknown TARGET"
226 #endif // TARGET*
227
228     assert(callerSPtoFPdelta <= 0);
229     return callerSPtoFPdelta;
230 }
231
232 //---------------------------------------------------------------------
233 // genCallerSPtoInitialSPdelta - return the offset from Caller-SP to Initial SP.
234 //
235 // This number will be negative.
236
237 int CodeGenInterface::genCallerSPtoInitialSPdelta() const
238 {
239     int callerSPtoSPdelta = 0;
240
241 #if defined(TARGET_ARM)
242     callerSPtoSPdelta -= genCountBits(regSet.rsMaskPreSpillRegs(true)) * REGSIZE_BYTES;
243     callerSPtoSPdelta -= genTotalFrameSize();
244 #elif defined(TARGET_X86)
245     callerSPtoSPdelta -= genTotalFrameSize();
246     callerSPtoSPdelta -= REGSIZE_BYTES; // caller-pushed return address
247
248     // compCalleeRegsPushed does not account for the frame pointer
249     // TODO-Cleanup: shouldn't this be part of genTotalFrameSize?
250     if (isFramePointerUsed())
251     {
252         callerSPtoSPdelta -= REGSIZE_BYTES;
253     }
254 #else
255 #error "Unknown TARGET"
256 #endif // TARGET*
257
258     assert(callerSPtoSPdelta <= 0);
259     return callerSPtoSPdelta;
260 }
261
262 #endif // defined(TARGET_X86) || defined(TARGET_ARM)
263
264 /*****************************************************************************
265  * Should we round simple operations (assignments, arithmetic operations, etc.)
266  */
267
268 // inline
269 // static
270 bool CodeGen::genShouldRoundFP()
271 {
272     RoundLevel roundLevel = getRoundFloatLevel();
273
274     switch (roundLevel)
275     {
276         case ROUND_NEVER:
277         case ROUND_CMP_CONST:
278         case ROUND_CMP:
279             return false;
280
281         default:
282             assert(roundLevel == ROUND_ALWAYS);
283             return true;
284     }
285 }
286
287 /*****************************************************************************
288  *
289  *  Initialize some global variables.
290  */
291
292 void CodeGen::genPrepForCompiler()
293 {
294     treeLifeUpdater = new (compiler, CMK_bitset) TreeLifeUpdater<true>(compiler);
295
296     /* Figure out which non-register variables hold pointers */
297
298     VarSetOps::AssignNoCopy(compiler, gcInfo.gcTrkStkPtrLcls, VarSetOps::MakeEmpty(compiler));
299
300     // Also, initialize gcTrkStkPtrLcls to include all tracked variables that do not fully live
301     // in a register (i.e. they live on the stack for all or part of their lifetime).
302     // Note that lvRegister indicates that a lclVar is in a register for its entire lifetime.
303
304     unsigned   varNum;
305     LclVarDsc* varDsc;
306     for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
307     {
308         if (varDsc->lvTracked || varDsc->lvIsRegCandidate())
309         {
310             if (!varDsc->lvRegister && compiler->lvaIsGCTracked(varDsc))
311             {
312                 VarSetOps::AddElemD(compiler, gcInfo.gcTrkStkPtrLcls, varDsc->lvVarIndex);
313             }
314         }
315     }
316     VarSetOps::AssignNoCopy(compiler, genLastLiveSet, VarSetOps::MakeEmpty(compiler));
317     genLastLiveMask = RBM_NONE;
318 #ifdef DEBUG
319     compiler->fgBBcountAtCodegen = compiler->fgBBcount;
320 #endif
321 }
322
323 //------------------------------------------------------------------------
324 // genMarkLabelsForCodegen: Mark labels required for codegen.
325 //
326 // Mark all blocks that require a label with BBF_HAS_LABEL. These are either blocks that are:
327 // 1. the target of jumps (fall-through flow doesn't require a label),
328 // 2. referenced labels such as for "switch" codegen,
329 // 3. needed to denote the range of EH regions to the VM.
330 // 4. needed to denote the range of code for alignment processing.
331 //
332 // No labels will be in the IR before now, but future codegen might annotate additional blocks
333 // with this flag, such as "switch" codegen, or codegen-created blocks from genCreateTempLabel().
334 // Also, the alignment processing code marks BBJ_COND fall-through labels elsewhere.
335 //
336 // To report exception handling information to the VM, we need the size of the exception
337 // handling regions. To compute that, we need to emit labels for the beginning block of
338 // an EH region, and the block that immediately follows a region. Go through the EH
339 // table and mark all these blocks with BBF_HAS_LABEL to make this happen.
340 //
341 // This code is closely couple with genReportEH() in the sense that any block
342 // that this procedure has determined it needs to have a label has to be selected
343 // using the same logic both here and in genReportEH(), so basically any time there is
344 // a change in the way we handle EH reporting, we have to keep the logic of these two
345 // methods 'in sync'.
346 //
347 // No blocks should be added or removed after this.
348 //
349 void CodeGen::genMarkLabelsForCodegen()
350 {
351     assert(!compiler->fgSafeBasicBlockCreation);
352
353     JITDUMP("Mark labels for codegen\n");
354
355 #ifdef DEBUG
356     // No label flags should be set before this.
357     for (BasicBlock* const block : compiler->Blocks())
358     {
359         assert((block->bbFlags & BBF_HAS_LABEL) == 0);
360     }
361 #endif // DEBUG
362
363     // The first block is special; it always needs a label. This is to properly set up GC info.
364     JITDUMP("  " FMT_BB " : first block\n", compiler->fgFirstBB->bbNum);
365     compiler->fgFirstBB->bbFlags |= BBF_HAS_LABEL;
366
367     // The current implementation of switch tables requires the first block to have a label so it
368     // can generate offsets to the switch label targets.
369     // (This is duplicative with the fact we always set the first block with a label above.)
370     // TODO-CQ: remove this when switches have been re-implemented to not use this.
371     if (compiler->fgHasSwitch)
372     {
373         JITDUMP("  " FMT_BB " : function has switch; mark first block\n", compiler->fgFirstBB->bbNum);
374         compiler->fgFirstBB->bbFlags |= BBF_HAS_LABEL;
375     }
376
377     for (BasicBlock* const block : compiler->Blocks())
378     {
379         switch (block->bbJumpKind)
380         {
381             case BBJ_ALWAYS: // This will also handle the BBJ_ALWAYS of a BBJ_CALLFINALLY/BBJ_ALWAYS pair.
382             case BBJ_COND:
383             case BBJ_EHCATCHRET:
384                 JITDUMP("  " FMT_BB " : branch target\n", block->bbJumpDest->bbNum);
385                 block->bbJumpDest->bbFlags |= BBF_HAS_LABEL;
386                 break;
387
388             case BBJ_SWITCH:
389                 for (BasicBlock* const bTarget : block->SwitchTargets())
390                 {
391                     JITDUMP("  " FMT_BB " : branch target\n", bTarget->bbNum);
392                     bTarget->bbFlags |= BBF_HAS_LABEL;
393                 }
394                 break;
395
396             case BBJ_CALLFINALLY:
397                 // The finally target itself will get marked by walking the EH table, below, and marking
398                 // all handler begins.
399                 CLANG_FORMAT_COMMENT_ANCHOR;
400
401 #if FEATURE_EH_CALLFINALLY_THUNKS
402                 {
403                     // For callfinally thunks, we need to mark the block following the callfinally/always pair,
404                     // as that's needed for identifying the range of the "duplicate finally" region in EH data.
405                     BasicBlock* bbToLabel = block->bbNext;
406                     if (block->isBBCallAlwaysPair())
407                     {
408                         bbToLabel = bbToLabel->bbNext; // skip the BBJ_ALWAYS
409                     }
410                     if (bbToLabel != nullptr)
411                     {
412                         JITDUMP("  " FMT_BB " : callfinally thunk region end\n", bbToLabel->bbNum);
413                         bbToLabel->bbFlags |= BBF_HAS_LABEL;
414                     }
415                 }
416 #endif // FEATURE_EH_CALLFINALLY_THUNKS
417
418                 break;
419
420             case BBJ_EHFINALLYRET:
421             case BBJ_EHFAULTRET:
422             case BBJ_EHFILTERRET:
423             case BBJ_RETURN:
424             case BBJ_THROW:
425             case BBJ_NONE:
426                 break;
427
428             default:
429                 noway_assert(!"Unexpected bbJumpKind");
430                 break;
431         }
432     }
433
434     // Walk all the exceptional code blocks and mark them, since they don't appear in the normal flow graph.
435     for (Compiler::AddCodeDsc* add = compiler->fgAddCodeList; add; add = add->acdNext)
436     {
437         JITDUMP("  " FMT_BB " : throw helper block\n", add->acdDstBlk->bbNum);
438         add->acdDstBlk->bbFlags |= BBF_HAS_LABEL;
439     }
440
441     for (EHblkDsc* const HBtab : EHClauses(compiler))
442     {
443         HBtab->ebdTryBeg->bbFlags |= BBF_HAS_LABEL;
444         HBtab->ebdHndBeg->bbFlags |= BBF_HAS_LABEL;
445
446         JITDUMP("  " FMT_BB " : try begin\n", HBtab->ebdTryBeg->bbNum);
447         JITDUMP("  " FMT_BB " : hnd begin\n", HBtab->ebdHndBeg->bbNum);
448
449         if (HBtab->ebdTryLast->bbNext != nullptr)
450         {
451             HBtab->ebdTryLast->bbNext->bbFlags |= BBF_HAS_LABEL;
452             JITDUMP("  " FMT_BB " : try end\n", HBtab->ebdTryLast->bbNext->bbNum);
453         }
454
455         if (HBtab->ebdHndLast->bbNext != nullptr)
456         {
457             HBtab->ebdHndLast->bbNext->bbFlags |= BBF_HAS_LABEL;
458             JITDUMP("  " FMT_BB " : hnd end\n", HBtab->ebdHndLast->bbNext->bbNum);
459         }
460
461         if (HBtab->HasFilter())
462         {
463             HBtab->ebdFilter->bbFlags |= BBF_HAS_LABEL;
464             JITDUMP("  " FMT_BB " : filter begin\n", HBtab->ebdFilter->bbNum);
465         }
466     }
467
468 #ifdef DEBUG
469     if (compiler->verbose)
470     {
471         printf("*************** After genMarkLabelsForCodegen()\n");
472         compiler->fgDispBasicBlocks();
473     }
474 #endif // DEBUG
475 }
476
477 void CodeGenInterface::genUpdateLife(GenTree* tree)
478 {
479     treeLifeUpdater->UpdateLife(tree);
480 }
481
482 void CodeGenInterface::genUpdateLife(VARSET_VALARG_TP newLife)
483 {
484     compiler->compUpdateLife</*ForCodeGen*/ true>(newLife);
485 }
486
487 // Return the register mask for the given register variable
488 // inline
489 regMaskTP CodeGenInterface::genGetRegMask(const LclVarDsc* varDsc)
490 {
491     regMaskTP regMask = RBM_NONE;
492
493     assert(varDsc->lvIsInReg());
494
495     regNumber reg = varDsc->GetRegNum();
496     if (genIsValidFloatReg(reg))
497     {
498         regMask = genRegMaskFloat(reg ARM_ARG(varDsc->GetRegisterType()));
499     }
500     else
501     {
502         regMask = genRegMask(reg);
503     }
504     return regMask;
505 }
506
507 // Return the register mask for the given lclVar or regVar tree node
508 // inline
509 regMaskTP CodeGenInterface::genGetRegMask(GenTree* tree)
510 {
511     assert(tree->gtOper == GT_LCL_VAR);
512
513     regMaskTP        regMask = RBM_NONE;
514     const LclVarDsc* varDsc  = compiler->lvaGetDesc(tree->AsLclVarCommon());
515     if (varDsc->lvPromoted)
516     {
517         for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i)
518         {
519             const LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(i);
520             noway_assert(fieldVarDsc->lvIsStructField);
521             if (fieldVarDsc->lvIsInReg())
522             {
523                 regMask |= genGetRegMask(fieldVarDsc);
524             }
525         }
526     }
527     else if (varDsc->lvIsInReg())
528     {
529         regMask = genGetRegMask(varDsc);
530     }
531     return regMask;
532 }
533
534 // The given lclVar is either going live (being born) or dying.
535 // It might be both going live and dying (that is, it is a dead store) under MinOpts.
536 // Update regSet.GetMaskVars() accordingly.
537 // inline
538 void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bool isDying DEBUGARG(GenTree* tree))
539 {
540     regMaskTP regMask = genGetRegMask(varDsc);
541
542 #ifdef DEBUG
543     if (compiler->verbose)
544     {
545         printf("\t\t\t\t\t\t\tV%02u in reg ", compiler->lvaGetLclNum(varDsc));
546
547         varDsc->PrintVarReg();
548         printf(" is becoming %s  ", (isDying) ? "dead" : "live");
549         Compiler::printTreeID(tree);
550         printf("\n");
551     }
552 #endif // DEBUG
553
554     if (isDying)
555     {
556         // We'd like to be able to assert the following, however if we are walking
557         // through a qmark/colon tree, we may encounter multiple last-use nodes.
558         // assert((regSet.GetMaskVars() & regMask) == regMask);
559         regSet.RemoveMaskVars(regMask);
560     }
561     else
562     {
563         // If this is going live, the register must not have a variable in it, except
564         // in the case of an exception or "spill at single-def" variable, which may be already treated
565         // as live in the register.
566         assert(varDsc->IsAlwaysAliveInMemory() || ((regSet.GetMaskVars() & regMask) == 0));
567         regSet.AddMaskVars(regMask);
568     }
569 }
570
571 //----------------------------------------------------------------------
572 // compHelperCallKillSet: Gets a register mask that represents the kill set for a helper call.
573 // Not all JIT Helper calls follow the standard ABI on the target architecture.
574 //
575 // TODO-CQ: Currently this list is incomplete (not all helpers calls are
576 //          enumerated) and not 100% accurate (some killsets are bigger than
577 //          what they really are).
578 //          There's some work to be done in several places in the JIT to
579 //          accurately track the registers that are getting killed by
580 //          helper calls:
581 //              a) LSRA needs several changes to accommodate more precise killsets
582 //                 for every helper call it sees (both explicitly [easy] and
583 //                 implicitly [hard])
584 //              b) Currently for AMD64, when we generate code for a helper call
585 //                 we're independently over-pessimizing the killsets of the call
586 //                 (independently from LSRA) and this needs changes
587 //                 both in CodeGenAmd64.cpp and emitx86.cpp.
588 //
589 //                 The best solution for this problem would be to try to centralize
590 //                 the killset information in a single place but then make the
591 //                 corresponding changes so every code generation phase is in sync
592 //                 about this.
593 //
594 //         The interim solution is to only add known helper calls that don't
595 //         follow the AMD64 ABI and actually trash registers that are supposed to be non-volatile.
596 //
597 // Arguments:
598 //   helper - The helper being inquired about
599 //
600 // Return Value:
601 //   Mask of register kills -- registers whose values are no longer guaranteed to be the same.
602 //
603 regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
604 {
605     switch (helper)
606     {
607         case CORINFO_HELP_ASSIGN_REF:
608         case CORINFO_HELP_CHECKED_ASSIGN_REF:
609             return RBM_CALLEE_TRASH_WRITEBARRIER;
610
611         case CORINFO_HELP_ASSIGN_BYREF:
612             return RBM_CALLEE_TRASH_WRITEBARRIER_BYREF;
613
614         case CORINFO_HELP_PROF_FCN_ENTER:
615             return RBM_PROFILER_ENTER_TRASH;
616
617         case CORINFO_HELP_PROF_FCN_LEAVE:
618             return RBM_PROFILER_LEAVE_TRASH;
619
620         case CORINFO_HELP_PROF_FCN_TAILCALL:
621             return RBM_PROFILER_TAILCALL_TRASH;
622
623 #ifdef TARGET_X86
624         case CORINFO_HELP_ASSIGN_REF_EAX:
625         case CORINFO_HELP_ASSIGN_REF_ECX:
626         case CORINFO_HELP_ASSIGN_REF_EBX:
627         case CORINFO_HELP_ASSIGN_REF_EBP:
628         case CORINFO_HELP_ASSIGN_REF_ESI:
629         case CORINFO_HELP_ASSIGN_REF_EDI:
630
631         case CORINFO_HELP_CHECKED_ASSIGN_REF_EAX:
632         case CORINFO_HELP_CHECKED_ASSIGN_REF_ECX:
633         case CORINFO_HELP_CHECKED_ASSIGN_REF_EBX:
634         case CORINFO_HELP_CHECKED_ASSIGN_REF_EBP:
635         case CORINFO_HELP_CHECKED_ASSIGN_REF_ESI:
636         case CORINFO_HELP_CHECKED_ASSIGN_REF_EDI:
637             return RBM_EDX;
638 #endif
639
640         case CORINFO_HELP_STOP_FOR_GC:
641             return RBM_STOP_FOR_GC_TRASH;
642
643         case CORINFO_HELP_INIT_PINVOKE_FRAME:
644             return RBM_INIT_PINVOKE_FRAME_TRASH;
645
646         case CORINFO_HELP_VALIDATE_INDIRECT_CALL:
647             return RBM_VALIDATE_INDIRECT_CALL_TRASH;
648
649         default:
650             return RBM_CALLEE_TRASH;
651     }
652 }
653
654 //------------------------------------------------------------------------
655 // compChangeLife: Compare the given "newLife" with last set of live variables and update
656 //  codeGen "gcInfo", siScopes, "regSet" with the new variable's homes/liveness.
657 //
658 // Arguments:
659 //    newLife - the new set of variables that are alive.
660 //
661 // Assumptions:
662 //    The set of live variables reflects the result of only emitted code, it should not be considering the becoming
663 //    live/dead of instructions that has not been emitted yet. This is used to ensure [) "VariableLiveRange"
664 //    intervals when calling "siStartVariableLiveRange" and "siEndVariableLiveRange".
665 //
666 // Notes:
667 //    If "ForCodeGen" is false, only "compCurLife" set (and no mask) will be setted.
668 //
669 template <bool ForCodeGen>
670 void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
671 {
672 #ifdef DEBUG
673     if (verbose)
674     {
675         printf("Change life %s ", VarSetOps::ToString(this, compCurLife));
676         dumpConvertedVarSet(this, compCurLife);
677         printf(" -> %s ", VarSetOps::ToString(this, newLife));
678         dumpConvertedVarSet(this, newLife);
679         printf("\n");
680     }
681 #endif // DEBUG
682
683     /* We should only be called when the live set has actually changed */
684
685     noway_assert(!VarSetOps::Equal(this, compCurLife, newLife));
686
687     if (!ForCodeGen)
688     {
689         VarSetOps::Assign(this, compCurLife, newLife);
690         return;
691     }
692
693     /* Figure out which variables are becoming live/dead at this point */
694
695     // deadSet = compCurLife - newLife
696     VARSET_TP deadSet(VarSetOps::Diff(this, compCurLife, newLife));
697
698     // bornSet = newLife - compCurLife
699     VARSET_TP bornSet(VarSetOps::Diff(this, newLife, compCurLife));
700
701     /* Can't simultaneously become live and dead at the same time */
702
703     // (deadSet UNION bornSet) != EMPTY
704     noway_assert(!VarSetOps::IsEmptyUnion(this, deadSet, bornSet));
705     // (deadSet INTERSECTION bornSet) == EMPTY
706     noway_assert(VarSetOps::IsEmptyIntersection(this, deadSet, bornSet));
707
708     VarSetOps::Assign(this, compCurLife, newLife);
709
710     // Handle the dying vars first, then the newly live vars.
711     // This is because, in the RyuJIT backend case, they may occupy registers that
712     // will be occupied by another var that is newly live.
713     VarSetOps::Iter deadIter(this, deadSet);
714     unsigned        deadVarIndex = 0;
715     while (deadIter.NextElem(&deadVarIndex))
716     {
717         unsigned   varNum     = lvaTrackedIndexToLclNum(deadVarIndex);
718         LclVarDsc* varDsc     = lvaGetDesc(varNum);
719         bool       isGCRef    = (varDsc->TypeGet() == TYP_REF);
720         bool       isByRef    = (varDsc->TypeGet() == TYP_BYREF);
721         bool       isInReg    = varDsc->lvIsInReg();
722         bool       isInMemory = !isInReg || varDsc->IsAlwaysAliveInMemory();
723
724         if (isInReg)
725         {
726             // TODO-Cleanup: Move the code from compUpdateLifeVar to genUpdateRegLife that updates the
727             // gc sets
728             regMaskTP regMask = varDsc->lvRegMask();
729             if (isGCRef)
730             {
731                 codeGen->gcInfo.gcRegGCrefSetCur &= ~regMask;
732             }
733             else if (isByRef)
734             {
735                 codeGen->gcInfo.gcRegByrefSetCur &= ~regMask;
736             }
737             codeGen->genUpdateRegLife(varDsc, false /*isBorn*/, true /*isDying*/ DEBUGARG(nullptr));
738         }
739         // Update the gcVarPtrSetCur if it is in memory.
740         if (isInMemory && (isGCRef || isByRef))
741         {
742             VarSetOps::RemoveElemD(this, codeGen->gcInfo.gcVarPtrSetCur, deadVarIndex);
743             JITDUMP("\t\t\t\t\t\t\tV%02u becoming dead\n", varNum);
744         }
745
746         codeGen->getVariableLiveKeeper()->siEndVariableLiveRange(varNum);
747     }
748
749     VarSetOps::Iter bornIter(this, bornSet);
750     unsigned        bornVarIndex = 0;
751     while (bornIter.NextElem(&bornVarIndex))
752     {
753         unsigned   varNum  = lvaTrackedIndexToLclNum(bornVarIndex);
754         LclVarDsc* varDsc  = lvaGetDesc(varNum);
755         bool       isGCRef = (varDsc->TypeGet() == TYP_REF);
756         bool       isByRef = (varDsc->TypeGet() == TYP_BYREF);
757
758         if (varDsc->lvIsInReg())
759         {
760             // If this variable is going live in a register, it is no longer live on the stack,
761             // unless it is an EH/"spill at single-def" var, which always remains live on the stack.
762             if (!varDsc->IsAlwaysAliveInMemory())
763             {
764 #ifdef DEBUG
765                 if (VarSetOps::IsMember(this, codeGen->gcInfo.gcVarPtrSetCur, bornVarIndex))
766                 {
767                     JITDUMP("\t\t\t\t\t\t\tRemoving V%02u from gcVarPtrSetCur\n", varNum);
768                 }
769 #endif // DEBUG
770                 VarSetOps::RemoveElemD(this, codeGen->gcInfo.gcVarPtrSetCur, bornVarIndex);
771             }
772             codeGen->genUpdateRegLife(varDsc, true /*isBorn*/, false /*isDying*/ DEBUGARG(nullptr));
773             regMaskTP regMask = varDsc->lvRegMask();
774             if (isGCRef)
775             {
776                 codeGen->gcInfo.gcRegGCrefSetCur |= regMask;
777             }
778             else if (isByRef)
779             {
780                 codeGen->gcInfo.gcRegByrefSetCur |= regMask;
781             }
782         }
783         else if (lvaIsGCTracked(varDsc))
784         {
785             // This isn't in a register, so update the gcVarPtrSetCur to show that it's live on the stack.
786             VarSetOps::AddElemD(this, codeGen->gcInfo.gcVarPtrSetCur, bornVarIndex);
787             JITDUMP("\t\t\t\t\t\t\tV%02u becoming live\n", varNum);
788         }
789
790         codeGen->getVariableLiveKeeper()->siStartVariableLiveRange(varDsc, varNum);
791     }
792 }
793
794 // Need an explicit instantiation.
795 template void Compiler::compChangeLife<true>(VARSET_VALARG_TP newLife);
796
797 /*****************************************************************************
798  *
799  *  Generate a spill.
800  */
801 void CodeGenInterface::spillReg(var_types type, TempDsc* tmp, regNumber reg)
802 {
803     GetEmitter()->emitIns_S_R(ins_Store(type), emitActualTypeSize(type), reg, tmp->tdTempNum(), 0);
804 }
805
806 /*****************************************************************************
807  *
808  *  Generate a reload.
809  */
810 void CodeGenInterface::reloadReg(var_types type, TempDsc* tmp, regNumber reg)
811 {
812     GetEmitter()->emitIns_R_S(ins_Load(type), emitActualTypeSize(type), reg, tmp->tdTempNum(), 0);
813 }
814
815 // inline
816 regNumber CodeGenInterface::genGetThisArgReg(GenTreeCall* call) const
817 {
818     return REG_ARG_0;
819 }
820
821 //----------------------------------------------------------------------
822 // getSpillTempDsc: get the TempDsc corresponding to a spilled tree.
823 //
824 // Arguments:
825 //   tree  -  spilled GenTree node
826 //
827 // Return Value:
828 //   TempDsc corresponding to tree
829 TempDsc* CodeGenInterface::getSpillTempDsc(GenTree* tree)
830 {
831     // tree must be in spilled state.
832     assert((tree->gtFlags & GTF_SPILLED) != 0);
833
834     // Get the tree's SpillDsc.
835     RegSet::SpillDsc* prevDsc;
836     RegSet::SpillDsc* spillDsc = regSet.rsGetSpillInfo(tree, tree->GetRegNum(), &prevDsc);
837     assert(spillDsc != nullptr);
838
839     // Get the temp desc.
840     TempDsc* temp = regSet.rsGetSpillTempWord(tree->GetRegNum(), spillDsc, prevDsc);
841     return temp;
842 }
843
844 /*****************************************************************************
845  *
846  *  The following can be used to create basic blocks that serve as labels for
847  *  the emitter. Use with caution - these are not real basic blocks!
848  *
849  */
850
851 // inline
852 BasicBlock* CodeGen::genCreateTempLabel()
853 {
854 #ifdef DEBUG
855     // These blocks don't affect FP
856     compiler->fgSafeBasicBlockCreation = true;
857 #endif
858
859     BasicBlock* block = compiler->bbNewBasicBlock(BBJ_NONE);
860
861 #ifdef DEBUG
862     compiler->fgSafeBasicBlockCreation = false;
863 #endif
864
865     JITDUMP("Mark " FMT_BB " as label: codegen temp block\n", block->bbNum);
866     block->bbFlags |= BBF_HAS_LABEL;
867
868     // Use coldness of current block, as this label will
869     // be contained in it.
870     block->bbFlags |= (compiler->compCurBB->bbFlags & BBF_COLD);
871
872 #ifdef DEBUG
873 #ifdef UNIX_X86_ABI
874     block->bbTgtStkDepth = (genStackLevel - curNestedAlignment) / sizeof(int);
875 #else
876     block->bbTgtStkDepth = genStackLevel / sizeof(int);
877 #endif
878 #endif
879     return block;
880 }
881
882 void CodeGen::genLogLabel(BasicBlock* bb)
883 {
884 #ifdef DEBUG
885     if (compiler->opts.dspCode)
886     {
887         printf("\n      L_M%03u_" FMT_BB ":\n", compiler->compMethodID, bb->bbNum);
888     }
889 #endif
890 }
891
892 // genDefineTempLabel: Define a label based on the current GC info tracked by
893 // the code generator.
894 //
895 // Arguments:
896 //     label - A label represented as a basic block. These are created with
897 //     genCreateTempLabel and are not normal basic blocks.
898 //
899 // Notes:
900 //     The label will be defined with the current GC info tracked by the code
901 //     generator. When the emitter sees this label it will thus remove any temporary
902 //     GC refs it is tracking in registers. For example, a call might produce a ref
903 //     in RAX which the emitter would track but which would not be tracked in
904 //     codegen's GC info since codegen would immediately copy it from RAX into its
905 //     home.
906 //
907 void CodeGen::genDefineTempLabel(BasicBlock* label)
908 {
909     genLogLabel(label);
910     label->bbEmitCookie = GetEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
911                                                      gcInfo.gcRegByrefSetCur, false DEBUG_ARG(label));
912 }
913
914 // genDefineInlineTempLabel: Define an inline label that does not affect the GC
915 // info.
916 //
917 // Arguments:
918 //     label - A label represented as a basic block. These are created with
919 //     genCreateTempLabel and are not normal basic blocks.
920 //
921 // Notes:
922 //     The emitter will continue to track GC info as if there was no label.
923 //
924 void CodeGen::genDefineInlineTempLabel(BasicBlock* label)
925 {
926     genLogLabel(label);
927     label->bbEmitCookie = GetEmitter()->emitAddInlineLabel();
928 }
929
930 //------------------------------------------------------------------------
931 // genAdjustStackLevel: Adjust the stack level, if required, for a throw helper block
932 //
933 // Arguments:
934 //    block - The BasicBlock for which we are about to generate code.
935 //
936 // Assumptions:
937 //    Must be called just prior to generating code for 'block'.
938 //
939 // Notes:
940 //    This only makes an adjustment if !FEATURE_FIXED_OUT_ARGS, if there is no frame pointer,
941 //    and if 'block' is a throw helper block with a non-zero stack level.
942
943 void CodeGen::genAdjustStackLevel(BasicBlock* block)
944 {
945 #if !FEATURE_FIXED_OUT_ARGS
946     // Check for inserted throw blocks and adjust genStackLevel.
947     CLANG_FORMAT_COMMENT_ANCHOR;
948
949 #if defined(UNIX_X86_ABI)
950     if (isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block))
951     {
952         // x86/Linux requires stack frames to be 16-byte aligned, but SP may be unaligned
953         // at this point if a jump to this block is made in the middle of pushing arguments.
954         //
955         // Here we restore SP to prevent potential stack alignment issues.
956         GetEmitter()->emitIns_R_AR(INS_lea, EA_PTRSIZE, REG_SPBASE, REG_FPBASE, -genSPtoFPdelta());
957     }
958 #endif
959
960     if (!isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block))
961     {
962         noway_assert(block->bbFlags & BBF_HAS_LABEL);
963
964         SetStackLevel(compiler->fgThrowHlpBlkStkLevel(block) * sizeof(int));
965
966         if (genStackLevel != 0)
967         {
968 #ifdef TARGET_X86
969             GetEmitter()->emitMarkStackLvl(genStackLevel);
970             inst_RV_IV(INS_add, REG_SPBASE, genStackLevel, EA_PTRSIZE);
971             SetStackLevel(0);
972 #else  // TARGET_X86
973             NYI("Need emitMarkStackLvl()");
974 #endif // TARGET_X86
975         }
976     }
977 #endif // !FEATURE_FIXED_OUT_ARGS
978 }
979
980 /*****************************************************************************
981  *
982  *  Take an address expression and try to find the best set of components to
983  *  form an address mode; returns non-zero if this is successful.
984  *
985  *  TODO-Cleanup: The RyuJIT backend never uses this to actually generate code.
986  *  Refactor this code so that the underlying analysis can be used in
987  *  the RyuJIT Backend to do lowering, instead of having to call this method with the
988  *  option to not generate the code.
989  *
990  *  'fold' specifies if it is OK to fold the array index which hangs off
991  *  a GT_NOP node.
992  *
993  *  If successful, the parameters will be set to the following values:
994  *
995  *      *rv1Ptr     ...     base operand
996  *      *rv2Ptr     ...     optional operand
997  *      *revPtr     ...     true if rv2 is before rv1 in the evaluation order
998  *      *mulPtr     ...     optional multiplier (2/4/8) for rv2
999  *                          Note that for [reg1 + reg2] and [reg1 + reg2 + icon], *mulPtr == 0.
1000  *      *cnsPtr     ...     integer constant [optional]
1001  *
1002  *  IMPORTANT NOTE: This routine doesn't generate any code, it merely
1003  *                  identifies the components that might be used to
1004  *                  form an address mode later on.
1005  */
1006
1007 bool CodeGen::genCreateAddrMode(
1008     GenTree* addr, bool fold, bool* revPtr, GenTree** rv1Ptr, GenTree** rv2Ptr, unsigned* mulPtr, ssize_t* cnsPtr)
1009 {
1010     /*
1011         The following indirections are valid address modes on x86/x64:
1012
1013             [                  icon]      * not handled here
1014             [reg                   ]
1015             [reg             + icon]
1016             [reg1 +     reg2       ]
1017             [reg1 +     reg2 + icon]
1018             [reg1 + 2 * reg2       ]
1019             [reg1 + 4 * reg2       ]
1020             [reg1 + 8 * reg2       ]
1021             [       2 * reg2 + icon]
1022             [       4 * reg2 + icon]
1023             [       8 * reg2 + icon]
1024             [reg1 + 2 * reg2 + icon]
1025             [reg1 + 4 * reg2 + icon]
1026             [reg1 + 8 * reg2 + icon]
1027
1028         The following indirections are valid address modes on arm64:
1029
1030             [reg]
1031             [reg  + icon]
1032             [reg1 + reg2]
1033             [reg1 + reg2 * natural-scale]
1034
1035      */
1036
1037     /* All indirect address modes require the address to be an addition */
1038
1039     if (!addr->OperIs(GT_ADD))
1040     {
1041         return false;
1042     }
1043
1044     GenTree* rv1 = nullptr;
1045     GenTree* rv2 = nullptr;
1046
1047     GenTree* op1;
1048     GenTree* op2;
1049
1050     ssize_t  cns;
1051     unsigned mul;
1052
1053     GenTree* tmp;
1054
1055     /* What order are the sub-operands to be evaluated */
1056
1057     if (addr->gtFlags & GTF_REVERSE_OPS)
1058     {
1059         op1 = addr->AsOp()->gtOp2;
1060         op2 = addr->AsOp()->gtOp1;
1061     }
1062     else
1063     {
1064         op1 = addr->AsOp()->gtOp1;
1065         op2 = addr->AsOp()->gtOp2;
1066     }
1067
1068     // Can't use indirect addressing mode as we need to check for overflow.
1069     // Also, can't use 'lea' as it doesn't set the flags.
1070
1071     if (addr->gtOverflow())
1072     {
1073         return false;
1074     }
1075
1076     bool rev = false; // Is op2 first in the evaluation order?
1077
1078     /*
1079         A complex address mode can combine the following operands:
1080
1081             op1     ...     base address
1082             op2     ...     optional scaled index
1083             mul     ...     optional multiplier (2/4/8) for op2
1084             cns     ...     optional displacement
1085
1086         Here we try to find such a set of operands and arrange for these
1087         to sit in registers.
1088      */
1089
1090     cns = 0;
1091     mul = 0;
1092
1093 AGAIN:
1094     /* We come back to 'AGAIN' if we have an add of a constant, and we are folding that
1095        constant, or we have gone through a GT_NOP or GT_COMMA node. We never come back
1096        here if we find a scaled index.
1097     */
1098     CLANG_FORMAT_COMMENT_ANCHOR;
1099
1100     assert(mul == 0);
1101
1102     /* Special case: keep constants as 'op2', but don't do this for constant handles
1103        because they don't fit I32 that we're going to check for below anyway. */
1104
1105     if (op1->IsCnsIntOrI() && !op1->IsIconHandle())
1106     {
1107         // Presumably op2 is assumed to not be a constant (shouldn't happen if we've done constant folding)?
1108         tmp = op1;
1109         op1 = op2;
1110         op2 = tmp;
1111     }
1112
1113     /* Check for an addition of a constant */
1114
1115     if (op2->IsIntCnsFitsInI32() && (op2->gtType != TYP_REF) && FitsIn<INT32>(cns + op2->AsIntConCommon()->IconValue()))
1116     {
1117         // We should not be building address modes out of non-foldable constants
1118         if (!op2->AsIntConCommon()->ImmedValCanBeFolded(compiler, addr->OperGet()))
1119         {
1120             assert(compiler->opts.compReloc);
1121             return false;
1122         }
1123
1124         /* We're adding a constant */
1125
1126         cns += op2->AsIntConCommon()->IconValue();
1127
1128 #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1129         if (cns == 0)
1130 #endif
1131         {
1132             /* Inspect the operand the constant is being added to */
1133
1134             switch (op1->gtOper)
1135             {
1136                 case GT_ADD:
1137
1138                     if (op1->gtOverflow())
1139                     {
1140                         break;
1141                     }
1142
1143                     op2 = op1->AsOp()->gtOp2;
1144                     op1 = op1->AsOp()->gtOp1;
1145
1146                     goto AGAIN;
1147
1148 #if !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
1149                 // TODO-ARM64-CQ, TODO-ARM-CQ: For now we don't try to create a scaled index.
1150                 case GT_MUL:
1151                     if (op1->gtOverflow())
1152                     {
1153                         return false; // Need overflow check
1154                     }
1155
1156                     FALLTHROUGH;
1157
1158                 case GT_LSH:
1159
1160                     mul = op1->GetScaledIndex();
1161                     if (mul)
1162                     {
1163                         /* We can use "[mul*rv2 + icon]" */
1164
1165                         rv1 = nullptr;
1166                         rv2 = op1->AsOp()->gtOp1;
1167
1168                         goto FOUND_AM;
1169                     }
1170                     break;
1171 #endif // !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
1172
1173                 default:
1174                     break;
1175             }
1176         }
1177
1178         /* The best we can do is "[rv1 + icon]" */
1179
1180         rv1 = op1;
1181         rv2 = nullptr;
1182
1183         goto FOUND_AM;
1184     }
1185
1186     // op2 is not a constant. So keep on trying.
1187
1188     /* Neither op1 nor op2 are sitting in a register right now */
1189
1190     switch (op1->gtOper)
1191     {
1192 #if !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
1193         // TODO-ARM64-CQ, TODO-ARM-CQ: For now we don't try to create a scaled index.
1194         case GT_ADD:
1195
1196             if (op1->gtOverflow())
1197             {
1198                 break;
1199             }
1200
1201             if (op1->AsOp()->gtOp2->IsIntCnsFitsInI32())
1202             {
1203                 GenTreeIntCon* addConst = op1->AsOp()->gtOp2->AsIntCon();
1204
1205                 if (addConst->ImmedValCanBeFolded(compiler, GT_ADD) && FitsIn<INT32>(cns + addConst->IconValue()))
1206                 {
1207                     cns += addConst->IconValue();
1208                     op1 = op1->AsOp()->gtOp1;
1209
1210                     goto AGAIN;
1211                 }
1212             }
1213             break;
1214
1215         case GT_MUL:
1216
1217             if (op1->gtOverflow())
1218             {
1219                 break;
1220             }
1221
1222             FALLTHROUGH;
1223
1224         case GT_LSH:
1225
1226             mul = op1->GetScaledIndex();
1227             if (mul)
1228             {
1229                 /* 'op1' is a scaled value */
1230
1231                 rv1 = op2;
1232                 rv2 = op1->AsOp()->gtOp1;
1233
1234                 int argScale;
1235                 while ((rv2->gtOper == GT_MUL || rv2->gtOper == GT_LSH) && (argScale = rv2->GetScaledIndex()) != 0)
1236                 {
1237                     if (jitIsScaleIndexMul(argScale * mul))
1238                     {
1239                         mul = mul * argScale;
1240                         rv2 = rv2->AsOp()->gtOp1;
1241                     }
1242                     else
1243                     {
1244                         break;
1245                     }
1246                 }
1247
1248                 noway_assert(rev == false);
1249                 rev = true;
1250
1251                 goto FOUND_AM;
1252             }
1253             break;
1254 #endif // !TARGET_ARMARCH && !TARGET_LOONGARCH64 && !TARGET_RISCV64
1255
1256         case GT_NOP:
1257
1258             op1 = op1->AsOp()->gtOp1;
1259             goto AGAIN;
1260
1261         case GT_COMMA:
1262
1263             op1 = op1->AsOp()->gtOp2;
1264             goto AGAIN;
1265
1266         default:
1267             break;
1268     }
1269
1270     noway_assert(op2);
1271     switch (op2->gtOper)
1272     {
1273 #if !defined(TARGET_ARMARCH) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
1274         // TODO-ARM64-CQ, TODO-ARM-CQ: For now we only handle MUL and LSH because
1275         // arm doesn't support both scale and offset at the same. Offset is handled
1276         // at the emitter as a peephole optimization.
1277         case GT_ADD:
1278
1279             if (op2->gtOverflow())
1280             {
1281                 break;
1282             }
1283
1284             if (op2->AsOp()->gtOp2->IsIntCnsFitsInI32())
1285             {
1286                 GenTreeIntCon* addConst = op2->AsOp()->gtOp2->AsIntCon();
1287
1288                 if (addConst->ImmedValCanBeFolded(compiler, GT_ADD) && FitsIn<INT32>(cns + addConst->IconValue()))
1289                 {
1290                     cns += addConst->IconValue();
1291                     op2 = op2->AsOp()->gtOp1;
1292                 }
1293
1294                 goto AGAIN;
1295             }
1296             break;
1297
1298         case GT_MUL:
1299
1300             if (op2->gtOverflow())
1301             {
1302                 break;
1303             }
1304
1305             FALLTHROUGH;
1306
1307         case GT_LSH:
1308
1309             mul = op2->GetScaledIndex();
1310             if (mul)
1311             {
1312                 // 'op2' is a scaled value...is it's argument also scaled?
1313                 int argScale;
1314                 rv2 = op2->AsOp()->gtOp1;
1315                 while ((rv2->gtOper == GT_MUL || rv2->gtOper == GT_LSH) && (argScale = rv2->GetScaledIndex()) != 0)
1316                 {
1317                     if (jitIsScaleIndexMul(argScale * mul))
1318                     {
1319                         mul = mul * argScale;
1320                         rv2 = rv2->AsOp()->gtOp1;
1321                     }
1322                     else
1323                     {
1324                         break;
1325                     }
1326                 }
1327
1328                 rv1 = op1;
1329
1330                 goto FOUND_AM;
1331             }
1332             break;
1333 #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64
1334
1335         case GT_NOP:
1336
1337             op2 = op2->AsOp()->gtOp1;
1338             goto AGAIN;
1339
1340         case GT_COMMA:
1341
1342             op2 = op2->AsOp()->gtOp2;
1343             goto AGAIN;
1344
1345         default:
1346             break;
1347     }
1348
1349     /* The best we can do "[rv1 + rv2]" or "[rv1 + rv2 + cns]" */
1350
1351     rv1 = op1;
1352     rv2 = op2;
1353 #ifdef TARGET_ARM64
1354     assert(cns == 0);
1355 #endif
1356
1357 FOUND_AM:
1358
1359     if (rv2)
1360     {
1361         // Make sure a GC address doesn't end up in 'rv2'
1362         if (varTypeIsGC(rv2->TypeGet()))
1363         {
1364             std::swap(rv1, rv2);
1365             rev = !rev;
1366         }
1367
1368         // Special case: constant array index (that is range-checked)
1369         if (fold)
1370         {
1371             // By default, assume index is rv2 and indexScale is mul (or 1 if mul is zero)
1372             GenTree* index      = rv2;
1373             ssize_t  indexScale = mul == 0 ? 1 : mul;
1374
1375             if (rv2->OperIs(GT_MUL, GT_LSH) && (rv2->gtGetOp2()->IsCnsIntOrI()))
1376             {
1377                 indexScale *= compiler->optGetArrayRefScaleAndIndex(rv2, &index DEBUGARG(false));
1378             }
1379
1380             // "index * 0" means index is zero
1381             if (indexScale == 0)
1382             {
1383                 mul = 0;
1384                 rv2 = nullptr;
1385             }
1386             else if (index->IsIntCnsFitsInI32())
1387             {
1388                 ssize_t constantIndex = index->AsIntConCommon()->IconValue() * indexScale;
1389                 if (constantIndex == 0)
1390                 {
1391                     // while scale is a non-zero constant, the actual index is zero so drop it
1392                     mul = 0;
1393                     rv2 = nullptr;
1394                 }
1395                 else if (FitsIn<INT32>(cns + constantIndex))
1396                 {
1397                     // Add the constant index to the accumulated offset value
1398                     cns += constantIndex;
1399                     // and get rid of index
1400                     mul = 0;
1401                     rv2 = nullptr;
1402                 }
1403             }
1404         }
1405     }
1406
1407     // We shouldn't have [rv2*1 + cns] - this is equivalent to [rv1 + cns]
1408     noway_assert(rv1 || mul != 1);
1409
1410     noway_assert(FitsIn<INT32>(cns));
1411
1412     if (rv1 == nullptr && rv2 == nullptr)
1413     {
1414         return false;
1415     }
1416
1417     /* Success - return the various components to the caller */
1418
1419     *revPtr = rev;
1420     *rv1Ptr = rv1;
1421     *rv2Ptr = rv2;
1422     *mulPtr = mul;
1423     *cnsPtr = cns;
1424
1425     return true;
1426 }
1427
1428 /*****************************************************************************
1429  *
1430  *  Generate an exit sequence for a return from a method (note: when compiling
1431  *  for speed there might be multiple exit points).
1432  */
1433
1434 void CodeGen::genExitCode(BasicBlock* block)
1435 {
1436     /* Just wrote the first instruction of the epilog - inform debugger
1437        Note that this may result in a duplicate IPmapping entry, and
1438        that this is ok  */
1439
1440     // For non-optimized debuggable code, there is only one epilog.
1441     genIPmappingAdd(IPmappingDscKind::Epilog, DebugInfo(), true);
1442
1443     bool jmpEpilog = ((block->bbFlags & BBF_HAS_JMP) != 0);
1444     if (compiler->getNeedsGSSecurityCookie())
1445     {
1446         genEmitGSCookieCheck(jmpEpilog);
1447
1448         if (jmpEpilog)
1449         {
1450             // Dev10 642944 -
1451             // The GS cookie check created a temp label that has no live
1452             // incoming GC registers, we need to fix that
1453
1454             unsigned   varNum;
1455             LclVarDsc* varDsc;
1456
1457             /* Figure out which register parameters hold pointers */
1458
1459             for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount && varDsc->lvIsRegArg;
1460                  varNum++, varDsc++)
1461             {
1462                 noway_assert(varDsc->lvIsParam);
1463
1464                 gcInfo.gcMarkRegPtrVal(varDsc->GetArgReg(), varDsc->TypeGet());
1465             }
1466
1467             GetEmitter()->emitThisGCrefRegs = GetEmitter()->emitInitGCrefRegs = gcInfo.gcRegGCrefSetCur;
1468             GetEmitter()->emitThisByrefRegs = GetEmitter()->emitInitByrefRegs = gcInfo.gcRegByrefSetCur;
1469         }
1470     }
1471
1472     genReserveEpilog(block);
1473 }
1474
1475 //------------------------------------------------------------------------
1476 // genJumpToThrowHlpBlk: Generate code for an out-of-line exception.
1477 //
1478 // Notes:
1479 //   For code that uses throw helper blocks, we share the helper blocks created by fgAddCodeRef().
1480 //   Otherwise, we generate the 'throw' inline.
1481 //
1482 // Arguments:
1483 //   jumpKind - jump kind to generate;
1484 //   codeKind - the special throw-helper kind;
1485 //   failBlk  - optional fail target block, if it is already known;
1486 //
1487 void CodeGen::genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, BasicBlock* failBlk)
1488 {
1489     bool useThrowHlpBlk = compiler->fgUseThrowHelperBlocks();
1490 #if defined(UNIX_X86_ABI) && defined(FEATURE_EH_FUNCLETS)
1491     // Inline exception-throwing code in funclet to make it possible to unwind funclet frames.
1492     useThrowHlpBlk = useThrowHlpBlk && (compiler->funCurrentFunc()->funKind == FUNC_ROOT);
1493 #endif // UNIX_X86_ABI && FEATURE_EH_FUNCLETS
1494
1495     if (useThrowHlpBlk)
1496     {
1497         // For code with throw helper blocks, find and use the helper block for
1498         // raising the exception. The block may be shared by other trees too.
1499
1500         BasicBlock* excpRaisingBlock;
1501
1502         if (failBlk != nullptr)
1503         {
1504             // We already know which block to jump to. Use that.
1505             excpRaisingBlock = failBlk;
1506
1507 #ifdef DEBUG
1508             Compiler::AddCodeDsc* add =
1509                 compiler->fgFindExcptnTarget(codeKind, compiler->bbThrowIndex(compiler->compCurBB));
1510             assert(excpRaisingBlock == add->acdDstBlk);
1511 #if !FEATURE_FIXED_OUT_ARGS
1512             assert(add->acdStkLvlInit || isFramePointerUsed());
1513 #endif // !FEATURE_FIXED_OUT_ARGS
1514 #endif // DEBUG
1515         }
1516         else
1517         {
1518             // Find the helper-block which raises the exception.
1519             Compiler::AddCodeDsc* add =
1520                 compiler->fgFindExcptnTarget(codeKind, compiler->bbThrowIndex(compiler->compCurBB));
1521             PREFIX_ASSUME_MSG((add != nullptr), ("ERROR: failed to find exception throw block"));
1522             excpRaisingBlock = add->acdDstBlk;
1523 #if !FEATURE_FIXED_OUT_ARGS
1524             assert(add->acdStkLvlInit || isFramePointerUsed());
1525 #endif // !FEATURE_FIXED_OUT_ARGS
1526         }
1527
1528         noway_assert(excpRaisingBlock != nullptr);
1529
1530         // Jump to the exception-throwing block on error.
1531         inst_JMP(jumpKind, excpRaisingBlock);
1532     }
1533     else
1534     {
1535         // The code to throw the exception will be generated inline, and
1536         // we will jump around it in the normal non-exception case.
1537
1538         BasicBlock*  tgtBlk          = nullptr;
1539         emitJumpKind reverseJumpKind = emitter::emitReverseJumpKind(jumpKind);
1540         if (reverseJumpKind != jumpKind)
1541         {
1542             tgtBlk = genCreateTempLabel();
1543             inst_JMP(reverseJumpKind, tgtBlk);
1544         }
1545
1546         genEmitHelperCall(compiler->acdHelper(codeKind), 0, EA_UNKNOWN);
1547
1548         // Define the spot for the normal non-exception case to jump to.
1549         if (tgtBlk != nullptr)
1550         {
1551             assert(reverseJumpKind != jumpKind);
1552             genDefineTempLabel(tgtBlk);
1553         }
1554     }
1555 }
1556
1557 /*****************************************************************************
1558  *
1559  * The last operation done was generating code for "tree" and that would
1560  * have set the flags. Check if the operation caused an overflow.
1561  */
1562
1563 #if !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
1564 // inline
1565 void CodeGen::genCheckOverflow(GenTree* tree)
1566 {
1567     // Overflow-check should be asked for this tree
1568     noway_assert(tree->gtOverflow());
1569
1570     const var_types type = tree->TypeGet();
1571
1572     // Overflow checks can only occur for the non-small types: (i.e. TYP_INT,TYP_LONG)
1573     noway_assert(!varTypeIsSmall(type));
1574
1575     emitJumpKind jumpKind;
1576
1577 #ifdef TARGET_ARM64
1578     if (tree->OperGet() == GT_MUL)
1579     {
1580         jumpKind = EJ_ne;
1581     }
1582     else
1583 #endif
1584     {
1585         bool isUnsignedOverflow = ((tree->gtFlags & GTF_UNSIGNED) != 0);
1586
1587 #if defined(TARGET_XARCH)
1588
1589         jumpKind = isUnsignedOverflow ? EJ_jb : EJ_jo;
1590
1591 #elif defined(TARGET_ARMARCH)
1592
1593         jumpKind = isUnsignedOverflow ? EJ_lo : EJ_vs;
1594
1595         if (jumpKind == EJ_lo)
1596         {
1597             if (tree->OperGet() != GT_SUB)
1598             {
1599                 jumpKind = EJ_hs;
1600             }
1601         }
1602 #endif // defined(TARGET_ARMARCH)
1603     }
1604
1605     // Jump to the block which will throw the exception
1606
1607     genJumpToThrowHlpBlk(jumpKind, SCK_OVERFLOW);
1608 }
1609 #endif
1610
1611 #if defined(FEATURE_EH_FUNCLETS)
1612
1613 /*****************************************************************************
1614  *
1615  *  Update the current funclet as needed by calling genUpdateCurrentFunclet().
1616  *  For non-BBF_FUNCLET_BEG blocks, it asserts that the current funclet
1617  *  is up-to-date.
1618  *
1619  */
1620
1621 void CodeGen::genUpdateCurrentFunclet(BasicBlock* block)
1622 {
1623     if (block->bbFlags & BBF_FUNCLET_BEG)
1624     {
1625         compiler->funSetCurrentFunc(compiler->funGetFuncIdx(block));
1626         if (compiler->funCurrentFunc()->funKind == FUNC_FILTER)
1627         {
1628             assert(compiler->ehGetDsc(compiler->funCurrentFunc()->funEHIndex)->ebdFilter == block);
1629         }
1630         else
1631         {
1632             // We shouldn't see FUNC_ROOT
1633             assert(compiler->funCurrentFunc()->funKind == FUNC_HANDLER);
1634             assert(compiler->ehGetDsc(compiler->funCurrentFunc()->funEHIndex)->ebdHndBeg == block);
1635         }
1636     }
1637     else
1638     {
1639         assert(compiler->compCurrFuncIdx <= compiler->compFuncInfoCount);
1640         if (compiler->funCurrentFunc()->funKind == FUNC_FILTER)
1641         {
1642             assert(compiler->ehGetDsc(compiler->funCurrentFunc()->funEHIndex)->InFilterRegionBBRange(block));
1643         }
1644         else if (compiler->funCurrentFunc()->funKind == FUNC_ROOT)
1645         {
1646             assert(!block->hasHndIndex());
1647         }
1648         else
1649         {
1650             assert(compiler->funCurrentFunc()->funKind == FUNC_HANDLER);
1651             assert(compiler->ehGetDsc(compiler->funCurrentFunc()->funEHIndex)->InHndRegionBBRange(block));
1652         }
1653     }
1654 }
1655
1656 #endif // FEATURE_EH_FUNCLETS
1657
1658 //----------------------------------------------------------------------
1659 // genGenerateCode: Generate code for the function.
1660 //
1661 // Arguments:
1662 //     codePtr [OUT] - address of generated code
1663 //     nativeSizeOfCode [OUT] - length of generated code in bytes
1664 //
1665 void CodeGen::genGenerateCode(void** codePtr, uint32_t* nativeSizeOfCode)
1666 {
1667
1668 #ifdef DEBUG
1669     if (verbose)
1670     {
1671         printf("*************** In genGenerateCode()\n");
1672         compiler->fgDispBasicBlocks(compiler->verboseTrees);
1673     }
1674 #endif
1675
1676     this->codePtr          = codePtr;
1677     this->nativeSizeOfCode = nativeSizeOfCode;
1678
1679     DoPhase(this, PHASE_GENERATE_CODE, &CodeGen::genGenerateMachineCode);
1680     DoPhase(this, PHASE_EMIT_CODE, &CodeGen::genEmitMachineCode);
1681     DoPhase(this, PHASE_EMIT_GCEH, &CodeGen::genEmitUnwindDebugGCandEH);
1682 }
1683
1684 //----------------------------------------------------------------------
1685 // genGenerateMachineCode -- determine which machine instructions to emit
1686 //
1687 void CodeGen::genGenerateMachineCode()
1688 {
1689 #ifdef DEBUG
1690     genInterruptibleUsed = true;
1691
1692     compiler->fgDebugCheckBBlist();
1693 #endif // DEBUG
1694
1695     /* This is the real thing */
1696
1697     genPrepForCompiler();
1698
1699     /* Prepare the emitter */
1700     GetEmitter()->Init();
1701 #ifdef DEBUG
1702     VarSetOps::AssignNoCopy(compiler, genTempOldLife, VarSetOps::MakeEmpty(compiler));
1703 #endif
1704
1705 #ifdef DEBUG
1706     if (compiler->opts.disAsmSpilled && regSet.rsNeededSpillReg)
1707     {
1708         compiler->opts.disAsm = true;
1709     }
1710 #endif
1711     compiler->compCurBB = compiler->fgFirstBB;
1712
1713     if (compiler->opts.disAsm)
1714     {
1715 #ifdef DEBUG
1716         const char* fullName = compiler->info.compFullName;
1717 #else
1718         const char* fullName = compiler->eeGetMethodFullName(compiler->info.compMethodHnd);
1719 #endif
1720
1721         printf("; Assembly listing for method %s (%s)\n", fullName, compiler->compGetTieringName(true));
1722
1723         printf("; Emitting ");
1724
1725         if (compiler->compCodeOpt() == Compiler::SMALL_CODE)
1726         {
1727             printf("SMALL_CODE");
1728         }
1729         else if (compiler->compCodeOpt() == Compiler::FAST_CODE)
1730         {
1731             printf("FAST_CODE");
1732         }
1733         else
1734         {
1735             printf("BLENDED_CODE");
1736         }
1737
1738         printf(" for ");
1739
1740 #if defined(TARGET_X86)
1741         if (compiler->canUseEvexEncoding())
1742         {
1743             printf("X86 with AVX512");
1744         }
1745         else if (compiler->canUseVexEncoding())
1746         {
1747             printf("X86 with AVX");
1748         }
1749         else
1750         {
1751             printf("generic X86");
1752         }
1753 #elif defined(TARGET_AMD64)
1754         if (compiler->canUseEvexEncoding())
1755         {
1756             printf("X64 with AVX512");
1757         }
1758         else if (compiler->canUseVexEncoding())
1759         {
1760             printf("X64 with AVX");
1761         }
1762         else
1763         {
1764             printf("generic X64");
1765         }
1766 #elif defined(TARGET_ARM)
1767         printf("generic ARM");
1768 #elif defined(TARGET_ARM64)
1769         printf("generic ARM64");
1770 #elif defined(TARGET_LOONGARCH64)
1771         printf("generic LOONGARCH64");
1772 #elif defined(TARGET_RISCV64)
1773         printf("generic RISCV64");
1774 #else
1775         printf("unknown architecture");
1776 #endif
1777
1778         if (TargetOS::IsWindows)
1779         {
1780             printf(" - Windows");
1781         }
1782         else if (TargetOS::IsMacOS)
1783         {
1784             printf(" - MacOS");
1785         }
1786         else if (TargetOS::IsUnix)
1787         {
1788             printf(" - Unix");
1789         }
1790
1791         printf("\n");
1792
1793         printf("; %s code\n", compiler->compGetTieringName(false));
1794
1795         if (compiler->IsTargetAbi(CORINFO_NATIVEAOT_ABI))
1796         {
1797             printf("; NativeAOT compilation\n");
1798         }
1799         else if (compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_READYTORUN))
1800         {
1801             printf("; ReadyToRun compilation\n");
1802         }
1803
1804         if (compiler->opts.IsOSR())
1805         {
1806             printf("; OSR variant for entry point 0x%x\n", compiler->info.compILEntry);
1807         }
1808
1809         if ((compiler->opts.compFlags & CLFLG_MAXOPT) == CLFLG_MAXOPT)
1810         {
1811             printf("; optimized code\n");
1812         }
1813         else if (compiler->opts.compDbgEnC)
1814         {
1815             printf("; EnC code\n");
1816         }
1817         else if (compiler->opts.compDbgCode)
1818         {
1819             printf("; debuggable code\n");
1820         }
1821
1822         if (compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && compiler->fgHaveProfileWeights())
1823         {
1824             printf("; optimized using %s\n", compiler->compGetPgoSourceName());
1825         }
1826
1827 #if DOUBLE_ALIGN
1828         if (compiler->genDoubleAlign())
1829             printf("; double-aligned frame\n");
1830         else
1831 #endif
1832             printf("; %s based frame\n", isFramePointerUsed() ? STR_FPBASE : STR_SPBASE);
1833
1834         if (GetInterruptible())
1835         {
1836             printf("; fully interruptible\n");
1837         }
1838         else
1839         {
1840             printf("; partially interruptible\n");
1841         }
1842
1843         if (compiler->fgHaveProfileWeights())
1844         {
1845             printf("; with %s: edge weights are %s, and fgCalledCount is " FMT_WT "\n",
1846                    compiler->compGetPgoSourceName(), compiler->fgHaveValidEdgeWeights ? "valid" : "invalid",
1847                    compiler->fgCalledCount);
1848         }
1849
1850         if (compiler->fgPgoFailReason != nullptr)
1851         {
1852             printf("; %s\n", compiler->fgPgoFailReason);
1853         }
1854
1855         if ((compiler->fgPgoInlineePgo + compiler->fgPgoInlineeNoPgo + compiler->fgPgoInlineeNoPgoSingleBlock) > 0)
1856         {
1857             printf("; %u inlinees with PGO data; %u single block inlinees; %u inlinees without PGO data\n",
1858                    compiler->fgPgoInlineePgo, compiler->fgPgoInlineeNoPgoSingleBlock, compiler->fgPgoInlineeNoPgo);
1859         }
1860
1861         if (compiler->opts.IsCFGEnabled())
1862         {
1863             printf("; control-flow guard enabled\n");
1864         }
1865
1866         if (compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALT_JIT))
1867         {
1868             printf("; invoked as altjit\n");
1869         }
1870     }
1871
1872     // We compute the final frame layout before code generation. This is because LSRA
1873     // has already computed exactly the maximum concurrent number of spill temps of each type that are
1874     // required during code generation. So, there is nothing left to estimate: we can be precise in the frame
1875     // layout. This helps us generate smaller code, and allocate, after code generation, a smaller amount of
1876     // memory from the VM.
1877
1878     genFinalizeFrame();
1879
1880     GetEmitter()->emitBegFN(isFramePointerUsed()
1881 #if defined(DEBUG)
1882                                 ,
1883                             (compiler->compCodeOpt() != Compiler::SMALL_CODE) &&
1884                                 !compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)
1885 #endif
1886                                 );
1887
1888     /* Now generate code for the function */
1889     genCodeForBBlist();
1890
1891 #ifdef DEBUG
1892     // After code generation, dump the frame layout again. It should be the same as before code generation, if code
1893     // generation hasn't touched it (it shouldn't!).
1894     if (verbose)
1895     {
1896         compiler->lvaTableDump();
1897     }
1898 #endif // DEBUG
1899
1900     /* We can now generate the function prolog and epilog */
1901     genGeneratePrologsAndEpilogs();
1902
1903     // check to see if any jumps can be removed
1904     GetEmitter()->emitRemoveJumpToNextInst();
1905
1906     /* Bind jump distances */
1907     GetEmitter()->emitJumpDistBind();
1908
1909 #if FEATURE_LOOP_ALIGN
1910     /* Perform alignment adjustments */
1911
1912     GetEmitter()->emitLoopAlignAdjustments();
1913 #endif
1914
1915     /* The code is now complete and final; it should not change after this. */
1916 }
1917
1918 //----------------------------------------------------------------------
1919 // genEmitMachineCode -- emit the actual machine instruction code
1920 //
1921 void CodeGen::genEmitMachineCode()
1922 {
1923     /* Compute the size of the code sections that we are going to ask the VM
1924        to allocate. Note that this might not be precisely the size of the
1925        code we emit, though it's fatal if we emit more code than the size we
1926        compute here.
1927        (Note: an example of a case where we emit less code would be useful.)
1928     */
1929
1930     GetEmitter()->emitComputeCodeSizes();
1931
1932 #ifdef DEBUG
1933     unsigned instrCount;
1934
1935     // Code to test or stress our ability to run a fallback compile.
1936     // We trigger the fallback here, before asking the VM for any memory,
1937     // because if not, we will leak mem, as the current codebase can't free
1938     // the mem after the emitter asks the VM for it. As this is only a stress
1939     // mode, we only want the functionality, and don't care about the relative
1940     // ugliness of having the failure here.
1941     if (!compiler->jitFallbackCompile)
1942     {
1943         // Use DOTNET_JitNoForceFallback=1 to prevent NOWAY assert testing from happening,
1944         // especially that caused by enabling JIT stress.
1945         if (!JitConfig.JitNoForceFallback())
1946         {
1947             if (JitConfig.JitForceFallback() || compiler->compStressCompile(Compiler::STRESS_GENERIC_VARN, 5))
1948             {
1949                 JITDUMP("\n\n*** forcing no-way fallback -- current jit request will be abandoned ***\n\n");
1950                 NO_WAY_NOASSERT("Stress failure");
1951             }
1952         }
1953     }
1954
1955 #endif // DEBUG
1956
1957     /* We've finished collecting all the unwind information for the function. Now reserve
1958        space for it from the VM.
1959     */
1960
1961     compiler->unwindReserve();
1962
1963     bool trackedStackPtrsContig; // are tracked stk-ptrs contiguous ?
1964
1965 #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1966     trackedStackPtrsContig = false;
1967 #elif defined(TARGET_ARM)
1968     // On arm due to prespilling of arguments, tracked stk-ptrs may not be contiguous
1969     trackedStackPtrsContig = !compiler->opts.compDbgEnC && !compiler->compIsProfilerHookNeeded();
1970 #else
1971     trackedStackPtrsContig = !compiler->opts.compDbgEnC;
1972 #endif
1973
1974     if (compiler->opts.disAsm && compiler->opts.disTesting)
1975     {
1976         printf("; BEGIN METHOD %s\n", compiler->eeGetMethodFullName(compiler->info.compMethodHnd));
1977     }
1978
1979     codeSize = GetEmitter()->emitEndCodeGen(compiler, trackedStackPtrsContig, GetInterruptible(),
1980                                             IsFullPtrRegMapRequired(), compiler->compHndBBtabCount, &prologSize,
1981                                             &epilogSize, codePtr, &coldCodePtr, &consPtr DEBUGARG(&instrCount));
1982
1983 #ifdef DEBUG
1984     assert(compiler->compCodeGenDone == false);
1985
1986     /* We're done generating code for this function */
1987     compiler->compCodeGenDone = true;
1988 #endif
1989
1990 #if defined(DEBUG) || defined(LATE_DISASM)
1991     // Add code size information into the Perf Score
1992     // All compPerfScore calculations must be performed using doubles
1993     compiler->info.compPerfScore += ((double)compiler->info.compTotalHotCodeSize * (double)PERFSCORE_CODESIZE_COST_HOT);
1994     compiler->info.compPerfScore +=
1995         ((double)compiler->info.compTotalColdCodeSize * (double)PERFSCORE_CODESIZE_COST_COLD);
1996 #endif // DEBUG || LATE_DISASM
1997
1998     if (compiler->opts.disAsm && compiler->opts.disTesting)
1999     {
2000         printf("; END METHOD %s\n", compiler->eeGetMethodFullName(compiler->info.compMethodHnd));
2001     }
2002
2003 #ifdef DEBUG
2004     if (compiler->opts.disAsm || verbose)
2005     {
2006         printf("\n; Total bytes of code %d, prolog size %d, PerfScore %.2f, instruction count %d, allocated bytes for "
2007                "code %d",
2008                codeSize, prologSize, compiler->info.compPerfScore, instrCount,
2009                GetEmitter()->emitTotalHotCodeSize + GetEmitter()->emitTotalColdCodeSize);
2010
2011 #if TRACK_LSRA_STATS
2012         if (JitConfig.DisplayLsraStats() == 3)
2013         {
2014             compiler->m_pLinearScan->dumpLsraStatsSummary(jitstdout());
2015         }
2016 #endif // TRACK_LSRA_STATS
2017
2018         printf(" (MethodHash=%08x) for method %s (%s)\n", compiler->info.compMethodHash(), compiler->info.compFullName,
2019                compiler->compGetTieringName(true));
2020
2021         printf("; ============================================================\n\n");
2022         printf(""); // in our logic this causes a flush
2023     }
2024
2025     if (verbose)
2026     {
2027         printf("*************** After end code gen, before unwindEmit()\n");
2028         GetEmitter()->emitDispIGlist(/* displayInstructions */ true);
2029     }
2030 #else
2031     if (compiler->opts.disAsm)
2032     {
2033         printf("\n; Total bytes of code %d\n\n", codeSize);
2034     }
2035 #endif
2036
2037     *nativeSizeOfCode                 = codeSize;
2038     compiler->info.compNativeCodeSize = (UNATIVE_OFFSET)codeSize;
2039
2040     // printf("%6u bytes of code generated for %s.%s\n", codeSize, compiler->info.compFullName);
2041
2042     // Make sure that the x86 alignment and cache prefetch optimization rules
2043     // were obeyed.
2044
2045     // Don't start a method in the last 7 bytes of a 16-byte alignment area
2046     //   unless we are generating SMALL_CODE
2047     // noway_assert( (((unsigned)(*codePtr) % 16) <= 8) || (compiler->compCodeOpt() == SMALL_CODE));
2048 }
2049
2050 //----------------------------------------------------------------------
2051 // genEmitUnwindDebugGCandEH: emit unwind, debug, gc, and EH info
2052 //
2053 void CodeGen::genEmitUnwindDebugGCandEH()
2054 {
2055     /* Now that the code is issued, we can finalize and emit the unwind data */
2056
2057     compiler->unwindEmit(*codePtr, coldCodePtr);
2058
2059     /* Finalize the line # tracking logic after we know the exact block sizes/offsets */
2060
2061     genIPmappingGen();
2062
2063     genReportRichDebugInfo();
2064
2065     /* Finalize the Local Var info in terms of generated code */
2066
2067     genSetScopeInfo();
2068
2069 #ifdef LATE_DISASM
2070     unsigned finalHotCodeSize;
2071     unsigned finalColdCodeSize;
2072     if (compiler->fgFirstColdBlock != nullptr)
2073     {
2074         // We did some hot/cold splitting. The hot section is always padded out to the
2075         // size we thought it would be, but the cold section is not.
2076         assert(codeSize <= compiler->info.compTotalHotCodeSize + compiler->info.compTotalColdCodeSize);
2077         assert(compiler->info.compTotalHotCodeSize > 0);
2078         assert(compiler->info.compTotalColdCodeSize > 0);
2079         finalHotCodeSize  = compiler->info.compTotalHotCodeSize;
2080         finalColdCodeSize = codeSize - finalHotCodeSize;
2081     }
2082     else
2083     {
2084         // No hot/cold splitting
2085         assert(codeSize <= compiler->info.compTotalHotCodeSize);
2086         assert(compiler->info.compTotalHotCodeSize > 0);
2087         assert(compiler->info.compTotalColdCodeSize == 0);
2088         finalHotCodeSize  = codeSize;
2089         finalColdCodeSize = 0;
2090     }
2091     getDisAssembler().disAsmCode((BYTE*)*codePtr, finalHotCodeSize, (BYTE*)coldCodePtr, finalColdCodeSize);
2092 #endif // LATE_DISASM
2093
2094     /* Report any exception handlers to the VM */
2095
2096     genReportEH();
2097
2098 #ifdef JIT32_GCENCODER
2099 #ifdef DEBUG
2100     void* infoPtr =
2101 #endif // DEBUG
2102 #endif
2103         // Create and store the GC info for this method.
2104         genCreateAndStoreGCInfo(codeSize, prologSize, epilogSize DEBUGARG(codePtr));
2105
2106 #ifdef DEBUG
2107     FILE* dmpf = jitstdout();
2108
2109     compiler->opts.dmpHex = false;
2110     if (!strcmp(compiler->info.compMethodName, "<name of method you want the hex dump for"))
2111     {
2112         FILE*   codf;
2113         errno_t ec = fopen_s(&codf, "C:\\JIT.COD", "at"); // NOTE: file append mode
2114         if (ec != 0)
2115         {
2116             assert(codf);
2117             dmpf                  = codf;
2118             compiler->opts.dmpHex = true;
2119         }
2120     }
2121     if (compiler->opts.dmpHex)
2122     {
2123         size_t consSize = GetEmitter()->emitDataSize();
2124
2125         fprintf(dmpf, "Generated code for %s:\n", compiler->info.compFullName);
2126         fprintf(dmpf, "\n");
2127
2128         if (codeSize)
2129         {
2130             fprintf(dmpf, "    Code  at %p [%04X bytes]\n", dspPtr(*codePtr), codeSize);
2131         }
2132         if (consSize)
2133         {
2134             fprintf(dmpf, "    Const at %p [%04X bytes]\n", dspPtr(consPtr), consSize);
2135         }
2136 #ifdef JIT32_GCENCODER
2137         size_t infoSize = compiler->compInfoBlkSize;
2138         if (infoSize)
2139             fprintf(dmpf, "    Info  at %p [%04X bytes]\n", dspPtr(infoPtr), infoSize);
2140 #endif // JIT32_GCENCODER
2141
2142         fprintf(dmpf, "\n");
2143
2144         if (codeSize)
2145         {
2146             hexDump(dmpf, "Code", (BYTE*)*codePtr, codeSize);
2147         }
2148         if (consSize)
2149         {
2150             hexDump(dmpf, "Const", (BYTE*)consPtr, consSize);
2151         }
2152 #ifdef JIT32_GCENCODER
2153         if (infoSize)
2154             hexDump(dmpf, "Info", (BYTE*)infoPtr, infoSize);
2155 #endif // JIT32_GCENCODER
2156
2157         fflush(dmpf);
2158     }
2159
2160     if (dmpf != jitstdout())
2161     {
2162         fclose(dmpf);
2163     }
2164
2165 #endif // DEBUG
2166
2167     /* Tell the emitter that we're done with this function */
2168
2169     GetEmitter()->emitEndFN();
2170
2171     /* Shut down the spill logic */
2172
2173     regSet.rsSpillDone();
2174
2175     /* Shut down the temp logic */
2176
2177     regSet.tmpDone();
2178
2179 #if DISPLAY_SIZES
2180
2181     size_t dataSize = GetEmitter()->emitDataSize();
2182     grossVMsize += compiler->info.compILCodeSize;
2183     totalNCsize += codeSize + dataSize + compiler->compInfoBlkSize;
2184     grossNCsize += codeSize + dataSize;
2185
2186 #endif // DISPLAY_SIZES
2187 }
2188
2189 /*****************************************************************************
2190  *
2191  *  Report EH clauses to the VM
2192  */
2193
2194 void CodeGen::genReportEH()
2195 {
2196     if (compiler->compHndBBtabCount == 0)
2197     {
2198         return;
2199     }
2200
2201 #ifdef DEBUG
2202     if (compiler->opts.dspEHTable)
2203     {
2204         printf("*************** EH table for %s\n", compiler->info.compFullName);
2205     }
2206 #endif // DEBUG
2207
2208     unsigned XTnum;
2209
2210     bool isNativeAOT = compiler->IsTargetAbi(CORINFO_NATIVEAOT_ABI);
2211
2212     unsigned EHCount = compiler->compHndBBtabCount;
2213
2214 #if defined(FEATURE_EH_FUNCLETS)
2215     // Count duplicated clauses. This uses the same logic as below, where we actually generate them for reporting to the
2216     // VM.
2217     unsigned duplicateClauseCount = 0;
2218     unsigned enclosingTryIndex;
2219
2220     // Duplicate clauses are not used by NativeAOT ABI
2221     if (!isNativeAOT)
2222     {
2223         for (XTnum = 0; XTnum < compiler->compHndBBtabCount; XTnum++)
2224         {
2225             for (enclosingTryIndex = compiler->ehTrueEnclosingTryIndexIL(XTnum); // find the true enclosing try index,
2226                                                                                  // ignoring 'mutual protect' trys
2227                  enclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX;
2228                  enclosingTryIndex = compiler->ehGetEnclosingTryIndex(enclosingTryIndex))
2229             {
2230                 ++duplicateClauseCount;
2231             }
2232         }
2233         EHCount += duplicateClauseCount;
2234     }
2235
2236 #if FEATURE_EH_CALLFINALLY_THUNKS
2237     unsigned clonedFinallyCount = 0;
2238
2239     // Duplicate clauses are not used by NativeAOT ABI
2240     if (!isNativeAOT)
2241     {
2242         // We don't keep track of how many cloned finally there are. So, go through and count.
2243         // We do a quick pass first through the EH table to see if there are any try/finally
2244         // clauses. If there aren't, we don't need to look for BBJ_CALLFINALLY.
2245
2246         bool anyFinallys = false;
2247         for (EHblkDsc* const HBtab : EHClauses(compiler))
2248         {
2249             if (HBtab->HasFinallyHandler())
2250             {
2251                 anyFinallys = true;
2252                 break;
2253             }
2254         }
2255         if (anyFinallys)
2256         {
2257             for (BasicBlock* const block : compiler->Blocks())
2258             {
2259                 if (block->bbJumpKind == BBJ_CALLFINALLY)
2260                 {
2261                     ++clonedFinallyCount;
2262                 }
2263             }
2264
2265             EHCount += clonedFinallyCount;
2266         }
2267     }
2268 #endif // FEATURE_EH_CALLFINALLY_THUNKS
2269
2270 #endif // FEATURE_EH_FUNCLETS
2271
2272 #ifdef DEBUG
2273     if (compiler->opts.dspEHTable)
2274     {
2275 #if defined(FEATURE_EH_FUNCLETS)
2276 #if FEATURE_EH_CALLFINALLY_THUNKS
2277         printf("%d EH table entries, %d duplicate clauses, %d cloned finallys, %d total EH entries reported to VM\n",
2278                compiler->compHndBBtabCount, duplicateClauseCount, clonedFinallyCount, EHCount);
2279         assert(compiler->compHndBBtabCount + duplicateClauseCount + clonedFinallyCount == EHCount);
2280 #else  // !FEATURE_EH_CALLFINALLY_THUNKS
2281         printf("%d EH table entries, %d duplicate clauses, %d total EH entries reported to VM\n",
2282                compiler->compHndBBtabCount, duplicateClauseCount, EHCount);
2283         assert(compiler->compHndBBtabCount + duplicateClauseCount == EHCount);
2284 #endif // !FEATURE_EH_CALLFINALLY_THUNKS
2285 #else  // !FEATURE_EH_FUNCLETS
2286         printf("%d EH table entries, %d total EH entries reported to VM\n", compiler->compHndBBtabCount, EHCount);
2287         assert(compiler->compHndBBtabCount == EHCount);
2288 #endif // !FEATURE_EH_FUNCLETS
2289     }
2290 #endif // DEBUG
2291
2292     // Tell the VM how many EH clauses to expect.
2293     compiler->eeSetEHcount(EHCount);
2294
2295     XTnum = 0; // This is the index we pass to the VM
2296
2297     for (EHblkDsc* const HBtab : EHClauses(compiler))
2298     {
2299         UNATIVE_OFFSET tryBeg, tryEnd, hndBeg, hndEnd, hndTyp;
2300
2301         tryBeg = compiler->ehCodeOffset(HBtab->ebdTryBeg);
2302         hndBeg = compiler->ehCodeOffset(HBtab->ebdHndBeg);
2303
2304         tryEnd = (HBtab->ebdTryLast == compiler->fgLastBB) ? compiler->info.compNativeCodeSize
2305                                                            : compiler->ehCodeOffset(HBtab->ebdTryLast->bbNext);
2306         hndEnd = (HBtab->ebdHndLast == compiler->fgLastBB) ? compiler->info.compNativeCodeSize
2307                                                            : compiler->ehCodeOffset(HBtab->ebdHndLast->bbNext);
2308
2309         if (HBtab->HasFilter())
2310         {
2311             hndTyp = compiler->ehCodeOffset(HBtab->ebdFilter);
2312         }
2313         else
2314         {
2315             hndTyp = HBtab->ebdTyp;
2316         }
2317
2318         CORINFO_EH_CLAUSE_FLAGS flags = ToCORINFO_EH_CLAUSE_FLAGS(HBtab->ebdHandlerType);
2319
2320         if (XTnum > 0)
2321         {
2322             // CORINFO_EH_CLAUSE_SAMETRY flag means that the current clause covers same
2323             // try block as the previous one. The runtime cannot reliably infer this information from
2324             // native code offsets because of different try blocks can have same offsets. Alternative
2325             // solution to this problem would be inserting extra nops to ensure that different try
2326             // blocks have different offsets.
2327             if (EHblkDsc::ebdIsSameTry(HBtab, HBtab - 1))
2328             {
2329                 // The SAMETRY bit should only be set on catch clauses. This is ensured in IL, where only 'catch' is
2330                 // allowed to be mutually-protect. E.g., the C# "try {} catch {} catch {} finally {}" actually exists in
2331                 // IL as "try { try {} catch {} catch {} } finally {}".
2332                 assert(HBtab->HasCatchHandler());
2333                 flags = (CORINFO_EH_CLAUSE_FLAGS)(flags | CORINFO_EH_CLAUSE_SAMETRY);
2334             }
2335         }
2336
2337         // Note that we reuse the CORINFO_EH_CLAUSE type, even though the names of
2338         // the fields aren't accurate.
2339
2340         CORINFO_EH_CLAUSE clause;
2341         clause.ClassToken    = hndTyp; /* filter offset is passed back here for filter-based exception handlers */
2342         clause.Flags         = flags;
2343         clause.TryOffset     = tryBeg;
2344         clause.TryLength     = tryEnd;
2345         clause.HandlerOffset = hndBeg;
2346         clause.HandlerLength = hndEnd;
2347
2348         assert(XTnum < EHCount);
2349
2350         // Tell the VM about this EH clause.
2351         compiler->eeSetEHinfo(XTnum, &clause);
2352
2353         ++XTnum;
2354     }
2355
2356 #if defined(FEATURE_EH_FUNCLETS)
2357     // Now output duplicated clauses.
2358     //
2359     // If a funclet has been created by moving a handler out of a try region that it was originally nested
2360     // within, then we need to report a "duplicate" clause representing the fact that an exception in that
2361     // handler can be caught by the 'try' it has been moved out of. This is because the original 'try' region
2362     // descriptor can only specify a single, contiguous protected range, but the funclet we've moved out is
2363     // no longer contiguous with the original 'try' region. The new EH descriptor will have the same handler
2364     // region as the enclosing try region's handler region. This is the sense in which it is duplicated:
2365     // there is now a "duplicate" clause with the same handler region as another, but a different 'try'
2366     // region.
2367     //
2368     // For example, consider this (capital letters represent an unknown code sequence, numbers identify a
2369     // try or handler region):
2370     //
2371     // A
2372     // try (1) {
2373     //   B
2374     //   try (2) {
2375     //     C
2376     //   } catch (3) {
2377     //     D
2378     //   } catch (4) {
2379     //     E
2380     //   }
2381     //   F
2382     // } catch (5) {
2383     //   G
2384     // }
2385     // H
2386     //
2387     // Here, we have try region (1) BCDEF protected by catch (5) G, and region (2) C protected
2388     // by catch (3) D and catch (4) E. Note that catch (4) E does *NOT* protect the code "D".
2389     // This is an example of 'mutually protect' regions. First, we move handlers (3) and (4)
2390     // to the end of the code. However, (3) and (4) are nested inside, and protected by, try (1). Again
2391     // note that (3) is not nested inside (4), despite ebdEnclosingTryIndex indicating that.
2392     // The code "D" and "E" won't be contiguous with the protected region for try (1) (which
2393     // will, after moving catch (3) AND (4), be BCF). Thus, we need to add a new EH descriptor
2394     // representing try (1) protecting the new funclets catch (3) and (4).
2395     // The code will be generated as follows:
2396     //
2397     // ABCFH // "main" code
2398     // D // funclet
2399     // E // funclet
2400     // G // funclet
2401     //
2402     // The EH regions are:
2403     //
2404     //  C -> D
2405     //  C -> E
2406     //  BCF -> G
2407     //  D -> G // "duplicate" clause
2408     //  E -> G // "duplicate" clause
2409     //
2410     // Note that we actually need to generate one of these additional "duplicate" clauses for every
2411     // region the funclet is nested in. Take this example:
2412     //
2413     //  A
2414     //  try (1) {
2415     //      B
2416     //      try (2,3) {
2417     //          C
2418     //          try (4) {
2419     //              D
2420     //              try (5,6) {
2421     //                  E
2422     //              } catch {
2423     //                  F
2424     //              } catch {
2425     //                  G
2426     //              }
2427     //              H
2428     //          } catch {
2429     //              I
2430     //          }
2431     //          J
2432     //      } catch {
2433     //          K
2434     //      } catch {
2435     //          L
2436     //      }
2437     //      M
2438     //  } catch {
2439     //      N
2440     //  }
2441     //  O
2442     //
2443     // When we pull out funclets, we get the following generated code:
2444     //
2445     // ABCDEHJMO // "main" function
2446     // F // funclet
2447     // G // funclet
2448     // I // funclet
2449     // K // funclet
2450     // L // funclet
2451     // N // funclet
2452     //
2453     // And the EH regions we report to the VM are (in order; main clauses
2454     // first in most-to-least nested order, funclets ("duplicated clauses")
2455     // last, in most-to-least nested) are:
2456     //
2457     //  E -> F
2458     //  E -> G
2459     //  DEH -> I
2460     //  CDEHJ -> K
2461     //  CDEHJ -> L
2462     //  BCDEHJM -> N
2463     //  F -> I // funclet clause #1 for F
2464     //  F -> K // funclet clause #2 for F
2465     //  F -> L // funclet clause #3 for F
2466     //  F -> N // funclet clause #4 for F
2467     //  G -> I // funclet clause #1 for G
2468     //  G -> K // funclet clause #2 for G
2469     //  G -> L // funclet clause #3 for G
2470     //  G -> N // funclet clause #4 for G
2471     //  I -> K // funclet clause #1 for I
2472     //  I -> L // funclet clause #2 for I
2473     //  I -> N // funclet clause #3 for I
2474     //  K -> N // funclet clause #1 for K
2475     //  L -> N // funclet clause #1 for L
2476     //
2477     // So whereas the IL had 6 EH clauses, we need to report 19 EH clauses to the VM.
2478     // Note that due to the nature of 'mutually protect' clauses, it would be incorrect
2479     // to add a clause "F -> G" because F is NOT protected by G, but we still have
2480     // both "F -> K" and "F -> L" because F IS protected by both of those handlers.
2481     //
2482     // The overall ordering of the clauses is still the same most-to-least nesting
2483     // after front-to-back start offset. Because we place the funclets at the end
2484     // these new clauses should also go at the end by this ordering.
2485     //
2486
2487     if (duplicateClauseCount > 0)
2488     {
2489         unsigned  reportedDuplicateClauseCount = 0; // How many duplicated clauses have we reported?
2490         unsigned  XTnum2;
2491         EHblkDsc* HBtab;
2492         for (XTnum2 = 0, HBtab = compiler->compHndBBtab; XTnum2 < compiler->compHndBBtabCount; XTnum2++, HBtab++)
2493         {
2494             unsigned enclosingTryIndex;
2495
2496             EHblkDsc* fletTab = compiler->ehGetDsc(XTnum2);
2497
2498             for (enclosingTryIndex = compiler->ehTrueEnclosingTryIndexIL(XTnum2); // find the true enclosing try index,
2499                                                                                   // ignoring 'mutual protect' trys
2500                  enclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX;
2501                  enclosingTryIndex = compiler->ehGetEnclosingTryIndex(enclosingTryIndex))
2502             {
2503                 // The funclet we moved out is nested in a try region, so create a new EH descriptor for the funclet
2504                 // that will have the enclosing try protecting the funclet.
2505
2506                 noway_assert(XTnum2 < enclosingTryIndex); // the enclosing region must be less nested, and hence have a
2507                                                           // greater EH table index
2508
2509                 EHblkDsc* encTab = compiler->ehGetDsc(enclosingTryIndex);
2510
2511                 // The try region is the handler of the funclet. Note that for filters, we don't protect the
2512                 // filter region, only the filter handler region. This is because exceptions in filters never
2513                 // escape; the VM swallows them.
2514
2515                 BasicBlock* bbTryBeg  = fletTab->ebdHndBeg;
2516                 BasicBlock* bbTryLast = fletTab->ebdHndLast;
2517
2518                 BasicBlock* bbHndBeg  = encTab->ebdHndBeg; // The handler region is the same as the enclosing try
2519                 BasicBlock* bbHndLast = encTab->ebdHndLast;
2520
2521                 UNATIVE_OFFSET tryBeg, tryEnd, hndBeg, hndEnd, hndTyp;
2522
2523                 tryBeg = compiler->ehCodeOffset(bbTryBeg);
2524                 hndBeg = compiler->ehCodeOffset(bbHndBeg);
2525
2526                 tryEnd = (bbTryLast == compiler->fgLastBB) ? compiler->info.compNativeCodeSize
2527                                                            : compiler->ehCodeOffset(bbTryLast->bbNext);
2528                 hndEnd = (bbHndLast == compiler->fgLastBB) ? compiler->info.compNativeCodeSize
2529                                                            : compiler->ehCodeOffset(bbHndLast->bbNext);
2530
2531                 if (encTab->HasFilter())
2532                 {
2533                     hndTyp = compiler->ehCodeOffset(encTab->ebdFilter);
2534                 }
2535                 else
2536                 {
2537                     hndTyp = encTab->ebdTyp;
2538                 }
2539
2540                 CORINFO_EH_CLAUSE_FLAGS flags = ToCORINFO_EH_CLAUSE_FLAGS(encTab->ebdHandlerType);
2541
2542                 // Tell the VM this is an extra clause caused by moving funclets out of line.
2543                 flags = (CORINFO_EH_CLAUSE_FLAGS)(flags | CORINFO_EH_CLAUSE_DUPLICATE);
2544
2545                 // Note that the JIT-EE interface reuses the CORINFO_EH_CLAUSE type, even though the names of
2546                 // the fields aren't really accurate. For example, we set "TryLength" to the offset of the
2547                 // instruction immediately after the 'try' body. So, it really could be more accurately named
2548                 // "TryEndOffset".
2549
2550                 CORINFO_EH_CLAUSE clause;
2551                 clause.ClassToken = hndTyp; /* filter offset is passed back here for filter-based exception handlers */
2552                 clause.Flags      = flags;
2553                 clause.TryOffset  = tryBeg;
2554                 clause.TryLength  = tryEnd;
2555                 clause.HandlerOffset = hndBeg;
2556                 clause.HandlerLength = hndEnd;
2557
2558                 assert(XTnum < EHCount);
2559
2560                 // Tell the VM about this EH clause (a duplicated clause).
2561                 compiler->eeSetEHinfo(XTnum, &clause);
2562
2563                 ++XTnum;
2564                 ++reportedDuplicateClauseCount;
2565
2566 #ifndef DEBUG
2567                 if (duplicateClauseCount == reportedDuplicateClauseCount)
2568                 {
2569                     break; // we've reported all of them; no need to continue looking
2570                 }
2571 #endif // !DEBUG
2572
2573             } // for each 'true' enclosing 'try'
2574         }     // for each EH table entry
2575
2576         assert(duplicateClauseCount == reportedDuplicateClauseCount);
2577     } // if (duplicateClauseCount > 0)
2578
2579 #if FEATURE_EH_CALLFINALLY_THUNKS
2580     if (clonedFinallyCount > 0)
2581     {
2582         unsigned reportedClonedFinallyCount = 0;
2583         for (BasicBlock* const block : compiler->Blocks())
2584         {
2585             if (block->bbJumpKind == BBJ_CALLFINALLY)
2586             {
2587                 UNATIVE_OFFSET hndBeg, hndEnd;
2588
2589                 hndBeg = compiler->ehCodeOffset(block);
2590
2591                 // How big is it? The BBJ_ALWAYS has a null bbEmitCookie! Look for the block after, which must be
2592                 // a label or jump target, since the BBJ_CALLFINALLY doesn't fall through.
2593                 BasicBlock* bbLabel = block->bbNext;
2594                 if (block->isBBCallAlwaysPair())
2595                 {
2596                     bbLabel = bbLabel->bbNext; // skip the BBJ_ALWAYS
2597                 }
2598                 if (bbLabel == nullptr)
2599                 {
2600                     hndEnd = compiler->info.compNativeCodeSize;
2601                 }
2602                 else
2603                 {
2604                     assert(bbLabel->bbEmitCookie != nullptr);
2605                     hndEnd = compiler->ehCodeOffset(bbLabel);
2606                 }
2607
2608                 CORINFO_EH_CLAUSE clause;
2609                 clause.ClassToken = 0; // unused
2610                 clause.Flags      = (CORINFO_EH_CLAUSE_FLAGS)(CORINFO_EH_CLAUSE_FINALLY | CORINFO_EH_CLAUSE_DUPLICATE);
2611                 clause.TryOffset  = hndBeg;
2612                 clause.TryLength  = hndBeg;
2613                 clause.HandlerOffset = hndBeg;
2614                 clause.HandlerLength = hndEnd;
2615
2616                 assert(XTnum < EHCount);
2617
2618                 // Tell the VM about this EH clause (a cloned finally clause).
2619                 compiler->eeSetEHinfo(XTnum, &clause);
2620
2621                 ++XTnum;
2622                 ++reportedClonedFinallyCount;
2623
2624 #ifndef DEBUG
2625                 if (clonedFinallyCount == reportedClonedFinallyCount)
2626                 {
2627                     break; // we're done; no need to keep looking
2628                 }
2629 #endif        // !DEBUG
2630             } // block is BBJ_CALLFINALLY
2631         }     // for each block
2632
2633         assert(clonedFinallyCount == reportedClonedFinallyCount);
2634     }  // if (clonedFinallyCount > 0)
2635 #endif // FEATURE_EH_CALLFINALLY_THUNKS
2636
2637 #endif // FEATURE_EH_FUNCLETS
2638
2639     assert(XTnum == EHCount);
2640 }
2641
2642 //----------------------------------------------------------------------
2643 // genUseOptimizedWriteBarriers: Determine if an optimized write barrier
2644 // helper should be used.
2645 //
2646 // Arguments:
2647 //   wbf - The WriteBarrierForm of the write (GT_STOREIND) that is happening.
2648 //
2649 // Return Value:
2650 //   true if an optimized write barrier helper should be used, false otherwise.
2651 //   Note: only x86 implements register-specific source optimized write
2652 //   barriers currently.
2653 //
2654 bool CodeGenInterface::genUseOptimizedWriteBarriers(GCInfo::WriteBarrierForm wbf)
2655 {
2656 #if defined(TARGET_X86) && NOGC_WRITE_BARRIERS
2657 #ifdef DEBUG
2658     return (wbf != GCInfo::WBF_NoBarrier_CheckNotHeapInDebug); // This one is always a call to a C++ method.
2659 #else
2660     return true;
2661 #endif
2662 #else
2663     return false;
2664 #endif
2665 }
2666
2667 //----------------------------------------------------------------------
2668 // genUseOptimizedWriteBarriers: Determine if an optimized write barrier
2669 // helper should be used.
2670 //
2671 // This has the same functionality as the version of
2672 // genUseOptimizedWriteBarriers that takes a WriteBarrierForm, but avoids
2673 // determining what the required write barrier form is, if possible.
2674 //
2675 // Arguments:
2676 //   store - the GT_STOREIND node
2677 //
2678 // Return Value:
2679 //   true if an optimized write barrier helper should be used, false otherwise.
2680 //   Note: only x86 implements register-specific source optimized write
2681 //   barriers currently.
2682 //
2683 bool CodeGenInterface::genUseOptimizedWriteBarriers(GenTreeStoreInd* store)
2684 {
2685 #if defined(TARGET_X86) && NOGC_WRITE_BARRIERS
2686 #ifdef DEBUG
2687     GCInfo::WriteBarrierForm wbf = compiler->codeGen->gcInfo.gcIsWriteBarrierCandidate(store);
2688     return (wbf != GCInfo::WBF_NoBarrier_CheckNotHeapInDebug); // This one is always a call to a C++ method.
2689 #else
2690     return true;
2691 #endif
2692 #else
2693     return false;
2694 #endif
2695 }
2696
2697 //----------------------------------------------------------------------
2698 // genWriteBarrierHelperForWriteBarrierForm: Given a write barrier form
2699 // return the corresponding helper.
2700 //
2701 // Arguments:
2702 //   wbf - the write barrier form
2703 //
2704 // Return Value:
2705 //   Write barrier helper to use.
2706 //
2707 // Note: do not call this function to get an optimized write barrier helper (e.g.,
2708 // for x86).
2709 //
2710 CorInfoHelpFunc CodeGenInterface::genWriteBarrierHelperForWriteBarrierForm(GCInfo::WriteBarrierForm wbf)
2711 {
2712     switch (wbf)
2713     {
2714         case GCInfo::WBF_BarrierChecked:
2715             return CORINFO_HELP_CHECKED_ASSIGN_REF;
2716
2717         case GCInfo::WBF_BarrierUnchecked:
2718             return CORINFO_HELP_ASSIGN_REF;
2719
2720 #ifdef DEBUG
2721         case GCInfo::WBF_NoBarrier_CheckNotHeapInDebug:
2722             return CORINFO_HELP_ASSIGN_REF_ENSURE_NONHEAP;
2723 #endif // DEBUG
2724
2725         default:
2726             unreached();
2727     }
2728 }
2729
2730 //----------------------------------------------------------------------
2731 // genGCWriteBarrier: Generate a write barrier for a node.
2732 //
2733 // Arguments:
2734 //   store - the GT_STOREIND node
2735 //   wbf   - already computed write barrier form to use
2736 //
2737 void CodeGen::genGCWriteBarrier(GenTreeStoreInd* store, GCInfo::WriteBarrierForm wbf)
2738 {
2739     CorInfoHelpFunc helper = genWriteBarrierHelperForWriteBarrierForm(wbf);
2740
2741 #ifdef FEATURE_COUNT_GC_WRITE_BARRIERS
2742     // Under FEATURE_COUNT_GC_WRITE_BARRIERS, we will add an extra argument to the
2743     // checked write barrier call denoting the kind of address being written to.
2744     //
2745     if (helper == CORINFO_HELP_CHECKED_ASSIGN_REF)
2746     {
2747         CheckedWriteBarrierKinds wbKind  = CWBKind_Unclassified;
2748         GenTree*                 tgtAddr = store->Addr();
2749
2750         while (tgtAddr->OperIs(GT_ADD, GT_LEA))
2751         {
2752             if (tgtAddr->OperIs(GT_LEA) && tgtAddr->AsAddrMode()->HasBase())
2753             {
2754                 tgtAddr = tgtAddr->AsAddrMode()->Base();
2755             }
2756             else if (tgtAddr->OperIs(GT_ADD) && tgtAddr->AsOp()->gtGetOp2()->IsCnsIntOrI())
2757             {
2758                 tgtAddr = tgtAddr->AsOp()->gtGetOp1();
2759             }
2760             else
2761             {
2762                 break;
2763             }
2764         }
2765
2766         if (tgtAddr->OperIs(GT_LCL_VAR))
2767         {
2768             unsigned   lclNum = tgtAddr->AsLclVar()->GetLclNum();
2769             LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
2770             if (lclNum == compiler->info.compRetBuffArg)
2771             {
2772                 wbKind = CWBKind_RetBuf
2773             }
2774             else if (varDsc->TypeGet() == TYP_BYREF)
2775             {
2776                 wbKind = varDsc->lvIsParam ? CWBKind_ByRefArg : CWBKind_OtherByRefLocal;
2777             }
2778         }
2779         else if (tgtAddr->OperIs(GT_LCL_ADDR))
2780         {
2781             // Ideally, we should have eliminated the barrier for this case.
2782             wbKind = CWBKind_AddrOfLocal;
2783         }
2784
2785 #if 0
2786 #ifdef DEBUG
2787         // Enable this to sample the unclassified trees.
2788         static int unclassifiedBarrierSite = 0;
2789         if (wbKind == CWBKind_Unclassified)
2790         {
2791             unclassifiedBarrierSite++;
2792             printf("unclassifiedBarrierSite = %d:\n", unclassifiedBarrierSite);
2793             compiler->gtDispTree(store);
2794             printf(""); // Flush.
2795             printf("\n");
2796         }
2797 #endif // DEBUG
2798 #endif // 0
2799
2800         AddStackLevel(4);
2801         inst_IV(INS_push, wbKind);
2802         genEmitHelperCall(helper,
2803                           4,           // argSize
2804                           EA_PTRSIZE); // retSize
2805         SubtractStackLevel(4);
2806         return;
2807     }
2808 #endif // FEATURE_COUNT_GC_WRITE_BARRIERS
2809
2810     genEmitHelperCall(helper,
2811                       0,           // argSize
2812                       EA_PTRSIZE); // retSize
2813 }
2814
2815 /*
2816 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2817 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2818 XX                                                                           XX
2819 XX                           Prolog / Epilog                                 XX
2820 XX                                                                           XX
2821 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2822 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2823 */
2824
2825 /*****************************************************************************
2826  *
2827  *  Generates code for moving incoming register arguments to their
2828  *  assigned location, in the function prolog.
2829  */
2830
2831 #ifdef _PREFAST_
2832 #pragma warning(push)
2833 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
2834 #endif
2835
2836 #if !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
2837 void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState)
2838 {
2839 #ifdef DEBUG
2840     if (verbose)
2841     {
2842         printf("*************** In genFnPrologCalleeRegArgs() for %s regs\n", regState->rsIsFloat ? "float" : "int");
2843     }
2844 #endif
2845
2846     unsigned  argMax;           // maximum argNum value plus 1, (including the RetBuffArg)
2847     unsigned  argNum;           // current argNum, always in [0..argMax-1]
2848     unsigned  fixedRetBufIndex; // argNum value used by the fixed return buffer argument (ARM64)
2849     unsigned  regArgNum;        // index into the regArgTab[] table
2850     regMaskTP regArgMaskLive = regState->rsCalleeRegArgMaskLiveIn;
2851     bool      doingFloat     = regState->rsIsFloat;
2852
2853     // We should be generating the prolog block when we are called
2854     assert(compiler->compGeneratingProlog);
2855
2856     // We expect to have some registers of the type we are doing, that are LiveIn, otherwise we don't need to be called.
2857     noway_assert(regArgMaskLive != 0);
2858
2859     // If a method has 3 args (and no fixed return buffer) then argMax is 3 and valid indexes are 0,1,2
2860     // If a method has a fixed return buffer (on ARM64) then argMax gets set to 9 and valid index are 0-8
2861     //
2862     // The regArgTab can always have unused entries,
2863     //    for example if an architecture always increments the arg register number but uses either
2864     //    an integer register or a floating point register to hold the next argument
2865     //    then with a mix of float and integer args you could have:
2866     //
2867     //    sampleMethod(int i, float x, int j, float y, int k, float z);
2868     //          r0, r2 and r4 as valid integer arguments with argMax as 5
2869     //      and f1, f3 and f5 and valid floating point arguments with argMax as 6
2870     //    The first one is doingFloat==false and the second one is doingFloat==true
2871     //
2872     //    If a fixed return buffer (in r8) was also present then the first one would become:
2873     //          r0, r2, r4 and r8 as valid integer arguments with argMax as 9
2874     //
2875
2876     argMax           = regState->rsCalleeRegArgCount;
2877     fixedRetBufIndex = (unsigned)-1; // Invalid value
2878
2879     // If necessary we will select a correct xtraReg for circular floating point args later.
2880     if (doingFloat)
2881     {
2882         xtraReg = REG_NA;
2883         noway_assert(argMax <= MAX_FLOAT_REG_ARG);
2884     }
2885     else // we are doing the integer registers
2886     {
2887         noway_assert(argMax <= MAX_REG_ARG);
2888         if (hasFixedRetBuffReg())
2889         {
2890             fixedRetBufIndex = theFixedRetBuffArgNum();
2891             // We have an additional integer register argument when hasFixedRetBuffReg() is true
2892             argMax = fixedRetBufIndex + 1;
2893             assert(argMax == (MAX_REG_ARG + 1));
2894         }
2895     }
2896
2897     //
2898     // Construct a table with the register arguments, for detecting circular and
2899     // non-circular dependencies between the register arguments. A dependency is when
2900     // an argument register Rn needs to be moved to register Rm that is also an argument
2901     // register. The table is constructed in the order the arguments are passed in
2902     // registers: the first register argument is in regArgTab[0], the second in
2903     // regArgTab[1], etc. Note that on ARM, a TYP_DOUBLE takes two entries, starting
2904     // at an even index. The regArgTab is indexed from 0 to argMax - 1.
2905     // Note that due to an extra argument register for ARM64 (i.e  theFixedRetBuffReg())
2906     // we have increased the allocated size of the regArgTab[] by one.
2907     //
2908     struct regArgElem
2909     {
2910         unsigned  varNum;  // index into compiler->lvaTable[] for this register argument
2911         var_types type;    // the Jit type of this regArgTab entry
2912         unsigned  trashBy; // index into this regArgTab[] table of the register that will be copied to this register.
2913                            // That is, for regArgTab[x].trashBy = y, argument register number 'y' will be copied to
2914                            // argument register number 'x'. Only used when circular = true.
2915         char slot;         // 0 means the register is not used for a register argument
2916                            // 1 means the first part of a register argument
2917                            // 2, 3 or 4  means the second,third or fourth part of a multireg argument
2918         bool stackArg;     // true if the argument gets homed to the stack
2919         bool writeThru;    // true if the argument gets homed to both stack and register
2920         bool processed;    // true after we've processed the argument (and it is in its final location)
2921         bool circular;     // true if this register participates in a circular dependency loop.
2922     } regArgTab[max(MAX_REG_ARG + 1, MAX_FLOAT_REG_ARG)] = {};
2923
2924     unsigned   varNum;
2925     LclVarDsc* varDsc;
2926
2927     for (varNum = 0; varNum < compiler->lvaCount; ++varNum)
2928     {
2929         varDsc = compiler->lvaGetDesc(varNum);
2930
2931         // Is this variable a register arg?
2932         if (!varDsc->lvIsParam)
2933         {
2934             continue;
2935         }
2936
2937         if (!varDsc->lvIsRegArg)
2938         {
2939             continue;
2940         }
2941
2942         // When we have a promoted struct we have two possible LclVars that can represent the incoming argument
2943         // in the regArgTab[], either the original TYP_STRUCT argument or the introduced lvStructField.
2944         // We will use the lvStructField if we have a TYPE_INDEPENDENT promoted struct field otherwise
2945         // use the original TYP_STRUCT argument.
2946         //
2947         if (varDsc->lvPromoted || varDsc->lvIsStructField)
2948         {
2949             LclVarDsc* parentVarDsc = varDsc;
2950             if (varDsc->lvIsStructField)
2951             {
2952                 assert(!varDsc->lvPromoted);
2953                 parentVarDsc = compiler->lvaGetDesc(varDsc->lvParentLcl);
2954             }
2955
2956             Compiler::lvaPromotionType promotionType = compiler->lvaGetPromotionType(parentVarDsc);
2957
2958             if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT)
2959             {
2960                 // For register arguments that are independent promoted structs we put the promoted field varNum in the
2961                 // regArgTab[]
2962                 if (varDsc->lvPromoted)
2963                 {
2964                     continue;
2965                 }
2966             }
2967             else
2968             {
2969                 // For register arguments that are not independent promoted structs we put the parent struct varNum in
2970                 // the regArgTab[]
2971                 if (varDsc->lvIsStructField)
2972                 {
2973                     continue;
2974                 }
2975             }
2976         }
2977
2978         var_types regType = compiler->mangleVarArgsType(varDsc->TypeGet());
2979         // Change regType to the HFA type when we have a HFA argument
2980         if (varDsc->lvIsHfaRegArg())
2981         {
2982 #if defined(TARGET_ARM64)
2983             if (TargetOS::IsWindows && compiler->info.compIsVarArgs)
2984             {
2985                 assert(!"Illegal incoming HFA arg encountered in Vararg method.");
2986             }
2987 #endif // defined(TARGET_ARM64)
2988             regType = varDsc->GetHfaType();
2989         }
2990
2991 #if defined(UNIX_AMD64_ABI)
2992         if (!varTypeIsStruct(regType))
2993 #endif // defined(UNIX_AMD64_ABI)
2994         {
2995             bool isFloatReg = emitter::isFloatReg(varDsc->GetArgReg());
2996
2997             if (isFloatReg != doingFloat)
2998             {
2999                 // A struct might be passed  partially in XMM register for System V calls.
3000                 // So a single arg might use both register files.
3001                 continue;
3002             }
3003             else if (isFloatReg != varTypeUsesFloatArgReg(regType))
3004             {
3005                 if (regType == TYP_FLOAT)
3006                 {
3007                     regType = TYP_INT;
3008                 }
3009                 else
3010                 {
3011                     assert(regType == TYP_DOUBLE);
3012                     regType = TYP_LONG;
3013                 }
3014             }
3015         }
3016
3017         int slots = 0;
3018
3019 #if defined(UNIX_AMD64_ABI)
3020         if (varTypeIsStruct(varDsc))
3021         {
3022             CORINFO_CLASS_HANDLE typeHnd;
3023             if (varDsc->lvIsStructField)
3024             {
3025                 // The only case we currently permit is a wrapped SIMD field,
3026                 // where we won't have the class handle available, so get it
3027                 // from the parent struct -- they will agree on ABI details.
3028                 LclVarDsc* parentDsc = compiler->lvaGetDesc(varDsc->lvParentLcl);
3029                 assert(varTypeIsSIMD(varDsc) && (parentDsc->lvFieldCnt == 1));
3030                 typeHnd = parentDsc->GetLayout()->GetClassHandle();
3031             }
3032             else
3033             {
3034                 typeHnd = varDsc->GetLayout()->GetClassHandle();
3035             }
3036             assert(typeHnd != nullptr);
3037             SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
3038             compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
3039             if (!structDesc.passedInRegisters)
3040             {
3041                 // The var is not passed in registers.
3042                 continue;
3043             }
3044
3045             unsigned firstRegSlot = 0;
3046             for (unsigned slotCounter = 0; slotCounter < structDesc.eightByteCount; slotCounter++)
3047             {
3048                 regNumber regNum = varDsc->lvRegNumForSlot(slotCounter);
3049                 var_types regType;
3050
3051 #ifdef FEATURE_SIMD
3052                 // Assumption 1:
3053                 // RyuJit backend depends on the assumption that on 64-Bit targets Vector3 size is rounded off
3054                 // to TARGET_POINTER_SIZE and hence Vector3 locals on stack can be treated as TYP_SIMD16 for
3055                 // reading and writing purposes.  Hence while homing a Vector3 type arg on stack we should
3056                 // home entire 16-bytes so that the upper-most 4-bytes will be zeroed when written to stack.
3057                 //
3058                 // Assumption 2:
3059                 // RyuJit backend is making another implicit assumption that Vector3 type args when passed in
3060                 // registers or on stack, the upper most 4-bytes will be zero.
3061                 //
3062                 // For P/Invoke return and Reverse P/Invoke argument passing, native compiler doesn't guarantee
3063                 // that upper 4-bytes of a Vector3 type struct is zero initialized and hence assumption 2 is
3064                 // invalid.
3065                 //
3066                 // RyuJIT x64 Windows: arguments are treated as passed by ref and hence read/written just 12
3067                 // bytes. In case of Vector3 returns, Caller allocates a zero initialized Vector3 local and
3068                 // passes it retBuf arg and Callee method writes only 12 bytes to retBuf. For this reason,
3069                 // there is no need to clear upper 4-bytes of Vector3 type args.
3070                 //
3071                 // RyuJIT x64 Unix: arguments are treated as passed by value and read/writen as if TYP_SIMD16.
3072                 // Vector3 return values are returned two return registers and Caller assembles them into a
3073                 // single xmm reg. Hence RyuJIT explicitly generates code to clears upper 4-bytes of Vector3
3074                 // type args in prolog and Vector3 type return value of a call
3075
3076                 if (varDsc->lvType == TYP_SIMD12)
3077                 {
3078                     regType = TYP_DOUBLE;
3079                 }
3080                 else
3081 #endif
3082                 {
3083                     regType = compiler->GetEightByteType(structDesc, slotCounter);
3084                 }
3085
3086                 regArgNum = genMapRegNumToRegArgNum(regNum, regType);
3087
3088                 if ((!doingFloat && (structDesc.IsIntegralSlot(slotCounter))) ||
3089                     (doingFloat && (structDesc.IsSseSlot(slotCounter))))
3090                 {
3091                     // Store the reg for the first slot.
3092                     if (slots == 0)
3093                     {
3094                         firstRegSlot = regArgNum;
3095                     }
3096
3097                     // Bingo - add it to our table
3098                     noway_assert(regArgNum < argMax);
3099                     noway_assert(regArgTab[regArgNum].slot == 0); // we better not have added it already (there better
3100                                                                   // not be multiple vars representing this argument
3101                                                                   // register)
3102                     regArgTab[regArgNum].varNum = varNum;
3103                     regArgTab[regArgNum].slot   = (char)(slotCounter + 1);
3104                     regArgTab[regArgNum].type   = regType;
3105                     slots++;
3106                 }
3107             }
3108
3109             if (slots == 0)
3110             {
3111                 continue; // Nothing to do for this regState set.
3112             }
3113
3114             regArgNum = firstRegSlot;
3115         }
3116         else
3117 #endif // defined(UNIX_AMD64_ABI)
3118         {
3119             // Bingo - add it to our table
3120             regArgNum = genMapRegNumToRegArgNum(varDsc->GetArgReg(), regType);
3121             slots     = 1;
3122
3123             if (TargetArchitecture::IsArm32)
3124             {
3125                 int lclSize = compiler->lvaLclSize(varNum);
3126                 if (lclSize > REGSIZE_BYTES)
3127                 {
3128                     slots = lclSize / REGSIZE_BYTES;
3129                 }
3130             }
3131 #if FEATURE_MULTIREG_ARGS
3132             else if (varDsc->lvIsMultiRegArg)
3133             {
3134                 if (varDsc->lvIsHfaRegArg())
3135                 {
3136                     // We have an HFA argument, set slots to the number of registers used
3137                     slots = varDsc->lvHfaSlots();
3138                 }
3139                 else
3140                 {
3141                     // Currently all non-HFA multireg structs are two registers in size (i.e. two slots)
3142                     assert(varDsc->lvSize() == (2 * TARGET_POINTER_SIZE));
3143                     // We have a non-HFA multireg argument, set slots to two
3144                     slots = 2;
3145                 }
3146             }
3147 #endif // FEATURE_MULTIREG_ARGS
3148
3149             // Handle args split between registers and stack. The arm64 fixed ret buf arg is never split.
3150             if (compFeatureArgSplit() && (fixedRetBufIndex != regArgNum))
3151             {
3152                 unsigned maxRegArgNum = doingFloat ? MAX_FLOAT_REG_ARG : MAX_REG_ARG;
3153                 if (regArgNum + slots > maxRegArgNum)
3154                 {
3155                     JITDUMP("Splitting V%02u: %u registers, %u stack slots\n", varNum, maxRegArgNum - regArgNum,
3156                             regArgNum + slots - maxRegArgNum);
3157                     slots = maxRegArgNum - regArgNum;
3158                 }
3159             }
3160
3161             // Note that regArgNum + 1 represents an argument index not an actual argument register;
3162             // see genMapRegArgNumToRegNum().
3163
3164             for (int i = 0; i < slots; i++)
3165             {
3166                 noway_assert((regArgNum + i) < argMax);
3167
3168                 // We better not have added it already (there better not be multiple vars representing this argument
3169                 // register)
3170                 noway_assert(regArgTab[regArgNum + i].slot == 0);
3171
3172                 regArgTab[regArgNum + i].varNum = varNum;
3173                 regArgTab[regArgNum + i].slot   = static_cast<char>(i + 1);
3174
3175                 regArgTab[regArgNum + i].type = regType; // Set the register type.
3176             }
3177         }
3178
3179         for (int i = 0; i < slots; i++)
3180         {
3181             regType          = regArgTab[regArgNum + i].type;
3182             regNumber regNum = genMapRegArgNumToRegNum(regArgNum + i, regType);
3183
3184 #if !defined(UNIX_AMD64_ABI)
3185             assert((i > 0) || (regNum == varDsc->GetArgReg()));
3186 #endif // defined(UNIX_AMD64_ABI)
3187
3188             // Is the arg dead on entry to the method ?
3189
3190             if ((regArgMaskLive & genRegMask(regNum)) == 0)
3191             {
3192                 if (varDsc->lvTrackedNonStruct())
3193                 {
3194                     // We may now see some tracked locals with zero refs.
3195                     // See Lowering::DoPhase. Tolerate these.
3196                     if (varDsc->lvRefCnt() > 0)
3197                     {
3198                         noway_assert(!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex));
3199                     }
3200                 }
3201                 else
3202                 {
3203 #ifdef TARGET_X86
3204                     noway_assert(varDsc->lvType == TYP_STRUCT);
3205 #else  // !TARGET_X86
3206                     // For LSRA, it may not be in regArgMaskLive if it has a zero
3207                     // refcnt.  This is in contrast with the non-LSRA case in which all
3208                     // non-tracked args are assumed live on entry.
3209                     noway_assert((varDsc->lvRefCnt() == 0) || (varDsc->lvType == TYP_STRUCT) ||
3210                                  (varDsc->IsAddressExposed() && compiler->info.compIsVarArgs) ||
3211                                  (varDsc->IsAddressExposed() && compiler->opts.compUseSoftFP));
3212 #endif // !TARGET_X86
3213                 }
3214                 // Mark it as processed and be done with it
3215                 regArgTab[regArgNum + i].processed = true;
3216                 goto NON_DEP;
3217             }
3218
3219 #ifdef TARGET_ARM
3220             // On the ARM when the varDsc is a struct arg (or pre-spilled due to varargs) the initReg/xtraReg
3221             // could be equal to GetArgReg(). The pre-spilled registers are also not considered live either since
3222             // they've already been spilled.
3223             //
3224             if ((regSet.rsMaskPreSpillRegs(false) & genRegMask(regNum)) == 0)
3225 #endif // TARGET_ARM
3226             {
3227 #if !defined(UNIX_AMD64_ABI)
3228                 noway_assert(xtraReg != (varDsc->GetArgReg() + i));
3229 #endif
3230                 noway_assert(regArgMaskLive & genRegMask(regNum));
3231             }
3232
3233             regArgTab[regArgNum + i].processed = false;
3234             regArgTab[regArgNum + i].writeThru = (varDsc->lvIsInReg() && varDsc->lvLiveInOutOfHndlr);
3235
3236             /* mark stack arguments since we will take care of those first */
3237             regArgTab[regArgNum + i].stackArg = (varDsc->lvIsInReg()) ? false : true;
3238
3239             /* If it goes on the stack or in a register that doesn't hold
3240              * an argument anymore -> CANNOT form a circular dependency */
3241
3242             if (varDsc->lvIsInReg() && (genRegMask(regNum) & regArgMaskLive))
3243             {
3244                 /* will trash another argument -> possible dependency
3245                  * We may need several passes after the table is constructed
3246                  * to decide on that */
3247
3248                 /* Maybe the argument stays in the register (IDEAL) */
3249
3250                 if ((i == 0) && (varDsc->GetRegNum() == regNum))
3251                 {
3252                     goto NON_DEP;
3253                 }
3254
3255 #if !defined(TARGET_64BIT)
3256                 if ((i == 1) && varTypeIsStruct(varDsc) && (varDsc->GetOtherReg() == regNum))
3257                 {
3258                     goto NON_DEP;
3259                 }
3260                 if ((i == 1) && (genActualType(varDsc->TypeGet()) == TYP_LONG) && (varDsc->GetOtherReg() == regNum))
3261                 {
3262                     goto NON_DEP;
3263                 }
3264
3265                 if ((i == 1) && (genActualType(varDsc->TypeGet()) == TYP_DOUBLE) &&
3266                     (REG_NEXT(varDsc->GetRegNum()) == regNum))
3267                 {
3268                     goto NON_DEP;
3269                 }
3270 #endif // !defined(TARGET_64BIT)
3271                 regArgTab[regArgNum + i].circular = true;
3272             }
3273             else
3274             {
3275             NON_DEP:
3276                 regArgTab[regArgNum + i].circular = false;
3277
3278                 /* mark the argument register as free */
3279                 regArgMaskLive &= ~genRegMask(regNum);
3280             }
3281         }
3282     }
3283
3284     /* Find the circular dependencies for the argument registers, if any.
3285      * A circular dependency is a set of registers R1, R2, ..., Rn
3286      * such that R1->R2 (that is, R1 needs to be moved to R2), R2->R3, ..., Rn->R1 */
3287
3288     bool change = true;
3289     if (regArgMaskLive)
3290     {
3291         /* Possible circular dependencies still exist; the previous pass was not enough
3292          * to filter them out. Use a "sieve" strategy to find all circular dependencies. */
3293
3294         while (change)
3295         {
3296             change = false;
3297
3298             for (argNum = 0; argNum < argMax; argNum++)
3299             {
3300                 // If we already marked the argument as non-circular then continue
3301
3302                 if (!regArgTab[argNum].circular)
3303                 {
3304                     continue;
3305                 }
3306
3307                 if (regArgTab[argNum].slot == 0) // Not a register argument
3308                 {
3309                     continue;
3310                 }
3311
3312                 varNum                     = regArgTab[argNum].varNum;
3313                 varDsc                     = compiler->lvaGetDesc(varNum);
3314                 const var_types varRegType = varDsc->GetRegisterType();
3315                 noway_assert(varDsc->lvIsParam && varDsc->lvIsRegArg);
3316
3317                 /* cannot possibly have stack arguments */
3318                 noway_assert(varDsc->lvIsInReg());
3319                 noway_assert(!regArgTab[argNum].stackArg);
3320
3321                 var_types regType = regArgTab[argNum].type;
3322                 regNumber regNum  = genMapRegArgNumToRegNum(argNum, regType);
3323
3324                 regNumber destRegNum = REG_NA;
3325                 if (varTypeIsPromotable(varDsc) &&
3326                     (compiler->lvaGetPromotionType(varDsc) == Compiler::PROMOTION_TYPE_INDEPENDENT))
3327                 {
3328                     assert(regArgTab[argNum].slot <= varDsc->lvFieldCnt);
3329                     LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varDsc->lvFieldLclStart + regArgTab[argNum].slot - 1);
3330                     destRegNum             = fieldVarDsc->GetRegNum();
3331                 }
3332                 else if (regArgTab[argNum].slot == 1)
3333                 {
3334                     destRegNum = varDsc->GetRegNum();
3335                 }
3336 #if defined(TARGET_ARM64) && defined(FEATURE_SIMD)
3337                 else if (varDsc->lvIsHfa())
3338                 {
3339                     // This must be a SIMD type that's fully enregistered, but is passed as an HFA.
3340                     // Each field will be inserted into the same destination register.
3341                     assert(varTypeIsSIMD(varDsc));
3342                     assert(regArgTab[argNum].slot <= (int)varDsc->lvHfaSlots());
3343                     assert(argNum > 0);
3344                     assert(regArgTab[argNum - 1].varNum == varNum);
3345                     regArgMaskLive &= ~genRegMask(regNum);
3346                     regArgTab[argNum].circular = false;
3347                     change                     = true;
3348                     continue;
3349                 }
3350 #elif defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
3351                 else
3352                 {
3353                     assert(regArgTab[argNum].slot == 2);
3354                     assert(argNum > 0);
3355                     assert(regArgTab[argNum - 1].slot == 1);
3356                     assert(regArgTab[argNum - 1].varNum == varNum);
3357                     assert((varRegType == TYP_SIMD12) || (varRegType == TYP_SIMD16));
3358                     regArgMaskLive &= ~genRegMask(regNum);
3359                     regArgTab[argNum].circular = false;
3360                     change                     = true;
3361                     continue;
3362                 }
3363 #endif // defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
3364 #if !defined(TARGET_64BIT)
3365                 else if (regArgTab[argNum].slot == 2 && genActualType(varDsc->TypeGet()) == TYP_LONG)
3366                 {
3367                     destRegNum = varDsc->GetOtherReg();
3368                 }
3369                 else
3370                 {
3371                     assert(regArgTab[argNum].slot == 2);
3372                     assert(varDsc->TypeGet() == TYP_DOUBLE);
3373                     destRegNum = REG_NEXT(varDsc->GetRegNum());
3374                 }
3375 #endif // !defined(TARGET_64BIT)
3376                 noway_assert(destRegNum != REG_NA);
3377                 if (genRegMask(destRegNum) & regArgMaskLive)
3378                 {
3379                     /* we are trashing a live argument register - record it */
3380                     unsigned destRegArgNum = genMapRegNumToRegArgNum(destRegNum, regType);
3381                     noway_assert(destRegArgNum < argMax);
3382                     regArgTab[destRegArgNum].trashBy = argNum;
3383                 }
3384                 else
3385                 {
3386                     /* argument goes to a free register */
3387                     regArgTab[argNum].circular = false;
3388                     change                     = true;
3389
3390                     /* mark the argument register as free */
3391                     regArgMaskLive &= ~genRegMask(regNum);
3392                 }
3393             }
3394         }
3395     }
3396
3397     /* At this point, everything that has the "circular" flag
3398      * set to "true" forms a circular dependency */
3399     CLANG_FORMAT_COMMENT_ANCHOR;
3400
3401 #ifdef DEBUG
3402     if (regArgMaskLive)
3403     {
3404         if (verbose)
3405         {
3406             printf("Circular dependencies found while home-ing the incoming arguments.\n");
3407         }
3408     }
3409 #endif
3410
3411     // LSRA allocates registers to incoming parameters in order and will not overwrite
3412     // a register still holding a live parameter.
3413
3414     noway_assert(((regArgMaskLive & RBM_FLTARG_REGS) == 0) &&
3415                  "Homing of float argument registers with circular dependencies not implemented.");
3416
3417     // Now move the arguments to their locations.
3418     // First consider ones that go on the stack since they may free some registers.
3419     // Also home writeThru args, since they're also homed to the stack.
3420
3421     regArgMaskLive = regState->rsCalleeRegArgMaskLiveIn; // reset the live in to what it was at the start
3422     for (argNum = 0; argNum < argMax; argNum++)
3423     {
3424         emitAttr size;
3425
3426 #if defined(UNIX_AMD64_ABI)
3427         // If this is the wrong register file, just continue.
3428         if (regArgTab[argNum].type == TYP_UNDEF)
3429         {
3430             // This could happen if the reg in regArgTab[argNum] is of the other register file -
3431             //     for System V register passed structs where the first reg is GPR and the second an XMM reg.
3432             // The next register file processing will process it.
3433             continue;
3434         }
3435 #endif // defined(UNIX_AMD64_ABI)
3436
3437         // If the arg is dead on entry to the method, skip it
3438
3439         if (regArgTab[argNum].processed)
3440         {
3441             continue;
3442         }
3443
3444         if (regArgTab[argNum].slot == 0) // Not a register argument
3445         {
3446             continue;
3447         }
3448
3449         varNum = regArgTab[argNum].varNum;
3450         varDsc = compiler->lvaGetDesc(varNum);
3451
3452 #ifndef TARGET_64BIT
3453         // If this arg is never on the stack, go to the next one.
3454         if (varDsc->lvType == TYP_LONG)
3455         {
3456             if (regArgTab[argNum].slot == 1 && !regArgTab[argNum].stackArg && !regArgTab[argNum].writeThru)
3457             {
3458                 continue;
3459             }
3460             else if (varDsc->GetOtherReg() != REG_STK)
3461             {
3462                 continue;
3463             }
3464         }
3465         else
3466 #endif // !TARGET_64BIT
3467         {
3468             // If this arg is never on the stack, go to the next one.
3469             if (!regArgTab[argNum].stackArg && !regArgTab[argNum].writeThru)
3470             {
3471                 continue;
3472             }
3473         }
3474
3475 #if defined(TARGET_ARM)
3476         if (varDsc->lvType == TYP_DOUBLE)
3477         {
3478             if (regArgTab[argNum].slot == 2)
3479             {
3480                 // We handled the entire double when processing the first half (slot == 1)
3481                 continue;
3482             }
3483         }
3484 #endif
3485
3486         noway_assert(regArgTab[argNum].circular == false);
3487
3488         noway_assert(varDsc->lvIsParam);
3489         noway_assert(varDsc->lvIsRegArg);
3490         noway_assert(varDsc->lvIsInReg() == false || varDsc->lvLiveInOutOfHndlr ||
3491                      (varDsc->lvType == TYP_LONG && varDsc->GetOtherReg() == REG_STK && regArgTab[argNum].slot == 2));
3492
3493         var_types storeType = TYP_UNDEF;
3494         unsigned  slotSize  = TARGET_POINTER_SIZE;
3495
3496         if (varTypeIsStruct(varDsc))
3497         {
3498             storeType = TYP_I_IMPL; // Default store type for a struct type is a pointer sized integer
3499 #if FEATURE_MULTIREG_ARGS
3500             // Must be <= MAX_PASS_MULTIREG_BYTES or else it wouldn't be passed in registers
3501             noway_assert(varDsc->lvSize() <= MAX_PASS_MULTIREG_BYTES);
3502 #endif // FEATURE_MULTIREG_ARGS
3503 #ifdef UNIX_AMD64_ABI
3504             storeType = regArgTab[argNum].type;
3505 #endif // !UNIX_AMD64_ABI
3506             if (varDsc->lvIsHfaRegArg())
3507             {
3508 #ifdef TARGET_ARM
3509                 // On ARM32 the storeType for HFA args is always TYP_FLOAT
3510                 storeType = TYP_FLOAT;
3511                 slotSize  = (unsigned)emitActualTypeSize(storeType);
3512 #else  // TARGET_ARM64
3513                 storeType = genActualType(varDsc->GetHfaType());
3514                 slotSize  = (unsigned)emitActualTypeSize(storeType);
3515 #endif // TARGET_ARM64
3516             }
3517         }
3518         else // Not a struct type
3519         {
3520             storeType = genActualType(regArgTab[argNum].type);
3521         }
3522         size = emitActualTypeSize(storeType);
3523 #ifdef TARGET_X86
3524         noway_assert(genTypeSize(storeType) == TARGET_POINTER_SIZE);
3525 #endif // TARGET_X86
3526
3527         regNumber srcRegNum = genMapRegArgNumToRegNum(argNum, storeType);
3528
3529         // Stack argument - if the ref count is 0 don't care about it
3530
3531         if (!varDsc->lvOnFrame)
3532         {
3533             noway_assert(varDsc->lvRefCnt() == 0);
3534         }
3535         else
3536         {
3537             // Since slot is typically 1, baseOffset is typically 0
3538             int baseOffset = (regArgTab[argNum].slot - 1) * slotSize;
3539
3540             GetEmitter()->emitIns_S_R(ins_Store(storeType), size, srcRegNum, varNum, baseOffset);
3541
3542 #ifndef UNIX_AMD64_ABI
3543             // Check if we are writing past the end of the struct
3544             if (varTypeIsStruct(varDsc))
3545             {
3546                 assert(varDsc->lvSize() >= baseOffset + (unsigned)size);
3547             }
3548 #endif // !UNIX_AMD64_ABI
3549         }
3550
3551         // Mark the argument as processed, and set it as no longer live in srcRegNum,
3552         // unless it is a writeThru var, in which case we home it to the stack, but
3553         // don't mark it as processed until below.
3554         if (!regArgTab[argNum].writeThru)
3555         {
3556             regArgTab[argNum].processed = true;
3557             regArgMaskLive &= ~genRegMask(srcRegNum);
3558         }
3559
3560 #if defined(TARGET_ARM)
3561         if ((storeType == TYP_DOUBLE) && !regArgTab[argNum].writeThru)
3562         {
3563             regArgTab[argNum + 1].processed = true;
3564             regArgMaskLive &= ~genRegMask(REG_NEXT(srcRegNum));
3565         }
3566 #endif
3567     }
3568
3569     /* Process any circular dependencies */
3570     if (regArgMaskLive)
3571     {
3572         unsigned    begReg, destReg, srcReg;
3573         unsigned    varNumDest, varNumSrc;
3574         LclVarDsc*  varDscDest;
3575         LclVarDsc*  varDscSrc;
3576         instruction insCopy = INS_mov;
3577
3578         if (doingFloat)
3579         {
3580 #ifndef UNIX_AMD64_ABI
3581             if (GlobalJitOptions::compFeatureHfa)
3582 #endif // !UNIX_AMD64_ABI
3583             {
3584                 insCopy = ins_Copy(TYP_DOUBLE);
3585                 // Compute xtraReg here when we have a float argument
3586                 assert(xtraReg == REG_NA);
3587
3588                 regMaskTP fpAvailMask;
3589
3590                 fpAvailMask = RBM_FLT_CALLEE_TRASH & ~regArgMaskLive;
3591                 if (GlobalJitOptions::compFeatureHfa)
3592                 {
3593                     fpAvailMask &= RBM_ALLDOUBLE;
3594                 }
3595
3596                 if (fpAvailMask == RBM_NONE)
3597                 {
3598                     fpAvailMask = RBM_ALLFLOAT & ~regArgMaskLive;
3599                     if (GlobalJitOptions::compFeatureHfa)
3600                     {
3601                         fpAvailMask &= RBM_ALLDOUBLE;
3602                     }
3603                 }
3604
3605                 assert(fpAvailMask != RBM_NONE);
3606
3607                 // We pick the lowest avail register number
3608                 regMaskTP tempMask = genFindLowestBit(fpAvailMask);
3609                 xtraReg            = genRegNumFromMask(tempMask);
3610             }
3611 #if defined(TARGET_X86)
3612             // This case shouldn't occur on x86 since NYI gets converted to an assert
3613             NYI("Homing circular FP registers via xtraReg");
3614 #endif
3615         }
3616
3617         for (argNum = 0; argNum < argMax; argNum++)
3618         {
3619             // If not a circular dependency then continue
3620             if (!regArgTab[argNum].circular)
3621             {
3622                 continue;
3623             }
3624
3625             // If already processed the dependency then continue
3626
3627             if (regArgTab[argNum].processed)
3628             {
3629                 continue;
3630             }
3631
3632             if (regArgTab[argNum].slot == 0) // Not a register argument
3633             {
3634                 continue;
3635             }
3636
3637             destReg = begReg = argNum;
3638             srcReg           = regArgTab[argNum].trashBy;
3639
3640             varNumDest = regArgTab[destReg].varNum;
3641             varDscDest = compiler->lvaGetDesc(varNumDest);
3642             noway_assert(varDscDest->lvIsParam && varDscDest->lvIsRegArg);
3643
3644             noway_assert(srcReg < argMax);
3645             varNumSrc = regArgTab[srcReg].varNum;
3646             varDscSrc = compiler->lvaGetDesc(varNumSrc);
3647             noway_assert(varDscSrc->lvIsParam && varDscSrc->lvIsRegArg);
3648
3649             emitAttr size = EA_PTRSIZE;
3650
3651 #ifdef TARGET_XARCH
3652             //
3653             // The following code relies upon the target architecture having an
3654             // 'xchg' instruction which directly swaps the values held in two registers.
3655             // On the ARM architecture we do not have such an instruction.
3656             //
3657             if (destReg == regArgTab[srcReg].trashBy)
3658             {
3659                 /* only 2 registers form the circular dependency - use "xchg" */
3660
3661                 varNum = regArgTab[argNum].varNum;
3662                 varDsc = compiler->lvaGetDesc(varNum);
3663                 noway_assert(varDsc->lvIsParam && varDsc->lvIsRegArg);
3664
3665                 noway_assert(genTypeSize(genActualType(varDscSrc->TypeGet())) <= REGSIZE_BYTES);
3666
3667                 /* Set "size" to indicate GC if one and only one of
3668                  * the operands is a pointer
3669                  * RATIONALE: If both are pointers, nothing changes in
3670                  * the GC pointer tracking. If only one is a pointer we
3671                  * have to "swap" the registers in the GC reg pointer mask
3672                  */
3673
3674                 if (varTypeGCtype(varDscSrc->TypeGet()) != varTypeGCtype(varDscDest->TypeGet()))
3675                 {
3676                     size = EA_GCREF;
3677                 }
3678
3679                 noway_assert(varDscDest->GetArgReg() == varDscSrc->GetRegNum());
3680
3681                 GetEmitter()->emitIns_R_R(INS_xchg, size, varDscSrc->GetRegNum(), varDscSrc->GetArgReg());
3682                 regSet.verifyRegUsed(varDscSrc->GetRegNum());
3683                 regSet.verifyRegUsed(varDscSrc->GetArgReg());
3684
3685                 /* mark both arguments as processed */
3686                 regArgTab[destReg].processed = true;
3687                 regArgTab[srcReg].processed  = true;
3688
3689                 regArgMaskLive &= ~genRegMask(varDscSrc->GetArgReg());
3690                 regArgMaskLive &= ~genRegMask(varDscDest->GetArgReg());
3691             }
3692             else
3693 #endif // TARGET_XARCH
3694             {
3695                 var_types destMemType = varDscDest->TypeGet();
3696
3697 #ifdef TARGET_ARM
3698                 bool cycleAllDouble = true; // assume the best
3699
3700                 unsigned iter = begReg;
3701                 do
3702                 {
3703                     if (compiler->lvaGetDesc(regArgTab[iter].varNum)->TypeGet() != TYP_DOUBLE)
3704                     {
3705                         cycleAllDouble = false;
3706                         break;
3707                     }
3708                     iter = regArgTab[iter].trashBy;
3709                 } while (iter != begReg);
3710
3711                 // We may treat doubles as floats for ARM because we could have partial circular
3712                 // dependencies of a float with a lo/hi part of the double. We mark the
3713                 // trashBy values for each slot of the double, so let the circular dependency
3714                 // logic work its way out for floats rather than doubles. If a cycle has all
3715                 // doubles, then optimize so that instead of two vmov.f32's to move a double,
3716                 // we can use one vmov.f64.
3717                 //
3718                 if (!cycleAllDouble && destMemType == TYP_DOUBLE)
3719                 {
3720                     destMemType = TYP_FLOAT;
3721                 }
3722 #endif // TARGET_ARM
3723
3724                 if (destMemType == TYP_REF)
3725                 {
3726                     size = EA_GCREF;
3727                 }
3728                 else if (destMemType == TYP_BYREF)
3729                 {
3730                     size = EA_BYREF;
3731                 }
3732                 else if (destMemType == TYP_DOUBLE)
3733                 {
3734                     size = EA_8BYTE;
3735                 }
3736                 else if (destMemType == TYP_FLOAT)
3737                 {
3738                     size = EA_4BYTE;
3739                 }
3740
3741                 /* move the dest reg (begReg) in the extra reg */
3742
3743                 assert(xtraReg != REG_NA);
3744
3745                 regNumber begRegNum = genMapRegArgNumToRegNum(begReg, destMemType);
3746
3747                 GetEmitter()->emitIns_Mov(insCopy, size, xtraReg, begRegNum, /* canSkip */ false);
3748
3749                 regSet.verifyRegUsed(xtraReg);
3750
3751                 *pXtraRegClobbered = true;
3752                 /* start moving everything to its right place */
3753
3754                 while (srcReg != begReg)
3755                 {
3756                     /* mov dest, src */
3757
3758                     regNumber destRegNum = genMapRegArgNumToRegNum(destReg, destMemType);
3759                     regNumber srcRegNum  = genMapRegArgNumToRegNum(srcReg, destMemType);
3760
3761                     GetEmitter()->emitIns_Mov(insCopy, size, destRegNum, srcRegNum, /* canSkip */ false);
3762
3763                     regSet.verifyRegUsed(destRegNum);
3764
3765                     /* mark 'src' as processed */
3766                     noway_assert(srcReg < argMax);
3767                     regArgTab[srcReg].processed = true;
3768 #ifdef TARGET_ARM
3769                     if (size == EA_8BYTE)
3770                         regArgTab[srcReg + 1].processed = true;
3771 #endif
3772                     regArgMaskLive &= ~genMapArgNumToRegMask(srcReg, destMemType);
3773
3774                     /* move to the next pair */
3775                     destReg = srcReg;
3776                     srcReg  = regArgTab[srcReg].trashBy;
3777
3778                     varDscDest  = varDscSrc;
3779                     destMemType = varDscDest->TypeGet();
3780 #ifdef TARGET_ARM
3781                     if (!cycleAllDouble && destMemType == TYP_DOUBLE)
3782                     {
3783                         destMemType = TYP_FLOAT;
3784                     }
3785 #endif
3786                     varNumSrc = regArgTab[srcReg].varNum;
3787                     varDscSrc = compiler->lvaGetDesc(varNumSrc);
3788                     noway_assert(varDscSrc->lvIsParam && varDscSrc->lvIsRegArg);
3789
3790                     if (destMemType == TYP_REF)
3791                     {
3792                         size = EA_GCREF;
3793                     }
3794                     else if (destMemType == TYP_DOUBLE)
3795                     {
3796                         size = EA_8BYTE;
3797                     }
3798                     else
3799                     {
3800                         size = EA_4BYTE;
3801                     }
3802                 }
3803
3804                 /* take care of the beginning register */
3805
3806                 noway_assert(srcReg == begReg);
3807
3808                 /* move the dest reg (begReg) in the extra reg */
3809
3810                 regNumber destRegNum = genMapRegArgNumToRegNum(destReg, destMemType);
3811
3812                 GetEmitter()->emitIns_Mov(insCopy, size, destRegNum, xtraReg, /* canSkip */ false);
3813
3814                 regSet.verifyRegUsed(destRegNum);
3815                 /* mark the beginning register as processed */
3816
3817                 regArgTab[srcReg].processed = true;
3818 #ifdef TARGET_ARM
3819                 if (size == EA_8BYTE)
3820                     regArgTab[srcReg + 1].processed = true;
3821 #endif
3822                 regArgMaskLive &= ~genMapArgNumToRegMask(srcReg, destMemType);
3823             }
3824         }
3825     }
3826
3827     /* Finally take care of the remaining arguments that must be enregistered */
3828     while (regArgMaskLive)
3829     {
3830         regMaskTP regArgMaskLiveSave = regArgMaskLive;
3831
3832         for (argNum = 0; argNum < argMax; argNum++)
3833         {
3834             /* If already processed go to the next one */
3835             if (regArgTab[argNum].processed)
3836             {
3837                 continue;
3838             }
3839
3840             if (regArgTab[argNum].slot == 0)
3841             { // Not a register argument
3842                 continue;
3843             }
3844
3845             varNum                     = regArgTab[argNum].varNum;
3846             varDsc                     = compiler->lvaGetDesc(varNum);
3847             const var_types regType    = regArgTab[argNum].type;
3848             const regNumber regNum     = genMapRegArgNumToRegNum(argNum, regType);
3849             const var_types varRegType = varDsc->GetRegisterType();
3850
3851 #if defined(UNIX_AMD64_ABI)
3852             if (regType == TYP_UNDEF)
3853             {
3854                 // This could happen if the reg in regArgTab[argNum] is of the other register file -
3855                 // for System V register passed structs where the first reg is GPR and the second an XMM reg.
3856                 // The next register file processing will process it.
3857                 regArgMaskLive &= ~genRegMask(regNum);
3858                 continue;
3859             }
3860 #endif // defined(UNIX_AMD64_ABI)
3861
3862             noway_assert(varDsc->lvIsParam && varDsc->lvIsRegArg);
3863 #ifdef TARGET_X86
3864             // On x86 we don't enregister args that are not pointer sized.
3865             noway_assert(genTypeSize(varDsc->GetStackSlotHomeType()) == TARGET_POINTER_SIZE);
3866 #endif // TARGET_X86
3867
3868             noway_assert(varDsc->lvIsInReg() && !regArgTab[argNum].circular);
3869
3870             /* Register argument - hopefully it stays in the same register */
3871             regNumber destRegNum  = REG_NA;
3872             var_types destMemType = varDsc->GetRegisterType();
3873
3874             if (regArgTab[argNum].slot == 1)
3875             {
3876                 destRegNum = varDsc->GetRegNum();
3877
3878 #ifdef TARGET_ARM
3879                 if (genActualType(destMemType) == TYP_DOUBLE && regArgTab[argNum + 1].processed)
3880                 {
3881                     // The second half of the double has already been processed! Treat this as a single.
3882                     destMemType = TYP_FLOAT;
3883                 }
3884 #endif // TARGET_ARM
3885             }
3886 #ifndef TARGET_64BIT
3887             else if (regArgTab[argNum].slot == 2 && genActualType(destMemType) == TYP_LONG)
3888             {
3889                 assert(genActualType(varDsc->TypeGet()) == TYP_LONG || genActualType(varDsc->TypeGet()) == TYP_DOUBLE);
3890                 if (genActualType(varDsc->TypeGet()) == TYP_DOUBLE)
3891                 {
3892                     destRegNum = regNum;
3893                 }
3894                 else
3895                 {
3896                     destRegNum = varDsc->GetOtherReg();
3897                 }
3898
3899                 assert(destRegNum != REG_STK);
3900             }
3901             else
3902             {
3903                 assert(regArgTab[argNum].slot == 2);
3904                 assert(destMemType == TYP_DOUBLE);
3905
3906                 // For doubles, we move the entire double using the argNum representing
3907                 // the first half of the double. There are two things we won't do:
3908                 // (1) move the double when the 1st half of the destination is free but the
3909                 // 2nd half is occupied, and (2) move the double when the 2nd half of the
3910                 // destination is free but the 1st half is occupied. Here we consider the
3911                 // case where the first half can't be moved initially because its target is
3912                 // still busy, but the second half can be moved. We wait until the entire
3913                 // double can be moved, if possible. For example, we have F0/F1 double moving to F2/F3,
3914                 // and F2 single moving to F16. When we process F0, its target F2 is busy,
3915                 // so we skip it on the first pass. When we process F1, its target F3 is
3916                 // available. However, we want to move F0/F1 all at once, so we skip it here.
3917                 // We process F2, which frees up F2. The next pass through, we process F0 and
3918                 // F2/F3 are empty, so we move it. Note that if half of a double is involved
3919                 // in a circularity with a single, then we will have already moved that half
3920                 // above, so we go ahead and move the remaining half as a single.
3921                 // Because there are no circularities left, we are guaranteed to terminate.
3922
3923                 assert(argNum > 0);
3924                 assert(regArgTab[argNum - 1].slot == 1);
3925
3926                 if (!regArgTab[argNum - 1].processed)
3927                 {
3928                     // The first half of the double hasn't been processed; try to be processed at the same time
3929                     continue;
3930                 }
3931
3932                 // The first half of the double has been processed but the second half hasn't!
3933                 // This could happen for double F2/F3 moving to F0/F1, and single F0 moving to F2.
3934                 // In that case, there is a F0/F2 loop that is not a double-only loop. The circular
3935                 // dependency logic above will move them as singles, leaving just F3 to move. Treat
3936                 // it as a single to finish the shuffling.
3937
3938                 destMemType = TYP_FLOAT;
3939                 destRegNum  = REG_NEXT(varDsc->GetRegNum());
3940             }
3941 #endif // !TARGET_64BIT
3942 #if (defined(UNIX_AMD64_ABI) || defined(TARGET_ARM64)) && defined(FEATURE_SIMD)
3943             else
3944             {
3945                 assert(regArgTab[argNum].slot == 2);
3946                 assert(argNum > 0);
3947                 assert(regArgTab[argNum - 1].slot == 1);
3948                 assert((varRegType == TYP_SIMD12) || (varRegType == TYP_SIMD16));
3949                 destRegNum = varDsc->GetRegNum();
3950                 noway_assert(regNum != destRegNum);
3951                 continue;
3952             }
3953 #endif // (defined(UNIX_AMD64_ABI) || defined(TARGET_ARM64)) && defined(FEATURE_SIMD)
3954             noway_assert(destRegNum != REG_NA);
3955             if (destRegNum != regNum)
3956             {
3957                 /* Cannot trash a currently live register argument.
3958                  * Skip this one until its target will be free
3959                  * which is guaranteed to happen since we have no circular dependencies. */
3960
3961                 regMaskTP destMask = genRegMask(destRegNum);
3962 #ifdef TARGET_ARM
3963                 // Don't process the double until both halves of the destination are clear.
3964                 if (genActualType(destMemType) == TYP_DOUBLE)
3965                 {
3966                     assert((destMask & RBM_DBL_REGS) != 0);
3967                     destMask |= genRegMask(REG_NEXT(destRegNum));
3968                 }
3969 #endif
3970
3971                 if (destMask & regArgMaskLive)
3972                 {
3973                     continue;
3974                 }
3975
3976                 /* Move it to the new register */
3977
3978                 emitAttr size = emitActualTypeSize(destMemType);
3979
3980 #if defined(TARGET_ARM64)
3981                 if (varTypeIsSIMD(varDsc) && argNum < (argMax - 1) && regArgTab[argNum + 1].slot == 2)
3982                 {
3983                     // For a SIMD type that is passed in two integer registers,
3984                     // Limit the copy below to the first 8 bytes from the first integer register.
3985                     // Handle the remaining 8 bytes from the second slot in the code further below
3986                     assert(EA_SIZE(size) >= 8);
3987                     size = EA_8BYTE;
3988                 }
3989 #endif
3990                 inst_Mov(destMemType, destRegNum, regNum, /* canSkip */ false, size);
3991             }
3992
3993             /* mark the argument as processed */
3994
3995             assert(!regArgTab[argNum].processed);
3996             regArgTab[argNum].processed = true;
3997             regArgMaskLive &= ~genRegMask(regNum);
3998 #if FEATURE_MULTIREG_ARGS
3999             int argRegCount = 1;
4000 #ifdef TARGET_ARM
4001             if (genActualType(destMemType) == TYP_DOUBLE)
4002             {
4003                 argRegCount = 2;
4004             }
4005 #endif
4006 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
4007             if (varTypeIsStruct(varDsc) && argNum < (argMax - 1) && regArgTab[argNum + 1].slot == 2)
4008             {
4009                 argRegCount          = 2;
4010                 int       nextArgNum = argNum + 1;
4011                 regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type);
4012                 noway_assert(regArgTab[nextArgNum].varNum == varNum);
4013                 // Emit a shufpd with a 0 immediate, which preserves the 0th element of the dest reg
4014                 // and moves the 0th element of the src reg into the 1st element of the dest reg.
4015                 GetEmitter()->emitIns_R_R_I(INS_shufpd, emitActualTypeSize(varRegType), destRegNum, nextRegNum, 0);
4016                 // Set destRegNum to regNum so that we skip the setting of the register below,
4017                 // but mark argNum as processed and clear regNum from the live mask.
4018                 destRegNum = regNum;
4019             }
4020 #endif // defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
4021 #ifdef TARGET_ARMARCH
4022             if (varDsc->lvIsHfa())
4023             {
4024                 // This includes both fixed-size SIMD types that are independently promoted, as well
4025                 // as other HFA structs.
4026                 argRegCount = varDsc->lvHfaSlots();
4027                 if (argNum < (argMax - argRegCount + 1))
4028                 {
4029                     if (compiler->lvaGetPromotionType(varDsc) == Compiler::PROMOTION_TYPE_INDEPENDENT)
4030                     {
4031                         // For an HFA type that is passed in multiple registers and promoted, we copy each field to its
4032                         // destination register.
4033                         for (int i = 0; i < argRegCount; i++)
4034                         {
4035                             int        nextArgNum  = argNum + i;
4036                             LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varDsc->lvFieldLclStart + i);
4037                             regNumber  nextRegNum  = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type);
4038                             destRegNum             = fieldVarDsc->GetRegNum();
4039                             noway_assert(regArgTab[nextArgNum].varNum == varNum);
4040                             noway_assert(genIsValidFloatReg(nextRegNum));
4041                             noway_assert(genIsValidFloatReg(destRegNum));
4042                             GetEmitter()->emitIns_Mov(INS_mov, EA_8BYTE, destRegNum, nextRegNum, /* canSkip */ false);
4043                         }
4044                     }
4045 #if defined(TARGET_ARM64) && defined(FEATURE_SIMD)
4046                     else
4047                     {
4048                         // For a SIMD type that is passed in multiple registers but enregistered as a vector,
4049                         // the code above copies the first argument register into the lower 4 or 8 bytes
4050                         // of the target register. Here we must handle the subsequent fields by
4051                         // inserting them into the upper bytes of the target SIMD floating point register.
4052                         argRegCount = varDsc->lvHfaSlots();
4053                         for (int i = 1; i < argRegCount; i++)
4054                         {
4055                             int         nextArgNum  = argNum + i;
4056                             regArgElem* nextArgElem = &regArgTab[nextArgNum];
4057                             var_types   nextArgType = nextArgElem->type;
4058                             regNumber   nextRegNum  = genMapRegArgNumToRegNum(nextArgNum, nextArgType);
4059                             noway_assert(nextArgElem->varNum == varNum);
4060                             noway_assert(genIsValidFloatReg(nextRegNum));
4061                             noway_assert(genIsValidFloatReg(destRegNum));
4062                             GetEmitter()->emitIns_R_R_I_I(INS_mov, EA_4BYTE, destRegNum, nextRegNum, i, 0);
4063                         }
4064                     }
4065 #endif // defined(TARGET_ARM64) && defined(FEATURE_SIMD)
4066                 }
4067             }
4068 #endif // TARGET_ARMARCH
4069
4070             // Mark the rest of the argument registers corresponding to this multi-reg type as
4071             // being processed and no longer live.
4072             for (int regSlot = 1; regSlot < argRegCount; regSlot++)
4073             {
4074                 int nextArgNum = argNum + regSlot;
4075                 assert(!regArgTab[nextArgNum].processed);
4076                 regArgTab[nextArgNum].processed = true;
4077                 regNumber nextRegNum            = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type);
4078                 regArgMaskLive &= ~genRegMask(nextRegNum);
4079             }
4080 #endif // FEATURE_MULTIREG_ARGS
4081         }
4082
4083         noway_assert(regArgMaskLiveSave != regArgMaskLive); // if it doesn't change, we have an infinite loop
4084     }
4085 }
4086 #endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64
4087
4088 #ifdef _PREFAST_
4089 #pragma warning(pop)
4090 #endif
4091
4092 /*****************************************************************************
4093  * If any incoming stack arguments live in registers, load them.
4094  */
4095 void CodeGen::genEnregisterIncomingStackArgs()
4096 {
4097 #ifdef DEBUG
4098     if (verbose)
4099     {
4100         printf("*************** In genEnregisterIncomingStackArgs()\n");
4101     }
4102 #endif
4103
4104     // OSR handles this specially -- see genEnregisterOSRArgsAndLocals
4105     //
4106     assert(!compiler->opts.IsOSR());
4107
4108     assert(compiler->compGeneratingProlog);
4109
4110     unsigned varNum = 0;
4111
4112 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
4113     int       tmp_offset = 0;
4114     regNumber tmp_reg    = REG_NA;
4115 #endif
4116
4117     for (LclVarDsc *varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
4118     {
4119         /* Is this variable a parameter? */
4120
4121         if (!varDsc->lvIsParam)
4122         {
4123             continue;
4124         }
4125
4126         /* If it's a register argument then it's already been taken care of.
4127            But, on Arm when under a profiler, we would have prespilled a register argument
4128            and hence here we need to load it from its prespilled location.
4129         */
4130         bool isPrespilledForProfiling = false;
4131 #if defined(TARGET_ARM) && defined(PROFILING_SUPPORTED)
4132         isPrespilledForProfiling =
4133             compiler->compIsProfilerHookNeeded() && compiler->lvaIsPreSpilled(varNum, regSet.rsMaskPreSpillRegs(false));
4134 #endif
4135
4136         if (varDsc->lvIsRegArg && !isPrespilledForProfiling)
4137         {
4138             continue;
4139         }
4140
4141         /* Has the parameter been assigned to a register? */
4142
4143         if (!varDsc->lvIsInReg())
4144         {
4145             continue;
4146         }
4147
4148         /* Is the variable dead on entry */
4149
4150         if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
4151         {
4152             continue;
4153         }
4154
4155         /* Load the incoming parameter into the register */
4156
4157         /* Figure out the home offset of the incoming argument */
4158
4159         regNumber regNum = varDsc->GetArgInitReg();
4160         assert(regNum != REG_STK);
4161
4162         var_types regType = varDsc->GetStackSlotHomeType();
4163 #ifdef TARGET_LOONGARCH64
4164         {
4165             bool FPbased;
4166             int  base = compiler->lvaFrameAddress(varNum, &FPbased);
4167
4168             if (emitter::isValidSimm12(base))
4169             {
4170                 GetEmitter()->emitIns_R_S(ins_Load(regType), emitTypeSize(regType), regNum, varNum, 0);
4171             }
4172             else
4173             {
4174                 if (tmp_reg == REG_NA)
4175                 {
4176                     regNumber reg2 = FPbased ? REG_FPBASE : REG_SPBASE;
4177                     tmp_offset     = base;
4178                     tmp_reg        = REG_R21;
4179
4180                     GetEmitter()->emitIns_I_la(EA_PTRSIZE, REG_R21, base);
4181                     GetEmitter()->emitIns_R_R_R(INS_add_d, EA_PTRSIZE, REG_R21, REG_R21, reg2);
4182                     GetEmitter()->emitIns_R_S(ins_Load(regType), emitTypeSize(regType), regNum, varNum, -8);
4183                 }
4184                 else
4185                 {
4186                     int baseOffset = -(base - tmp_offset) - 8;
4187                     GetEmitter()->emitIns_R_S(ins_Load(regType), emitTypeSize(regType), regNum, varNum, baseOffset);
4188                 }
4189             }
4190         }
4191 #else // !TARGET_LOONGARCH64
4192         GetEmitter()->emitIns_R_S(ins_Load(regType), emitTypeSize(regType), regNum, varNum, 0);
4193 #endif // !TARGET_LOONGARCH64
4194
4195         regSet.verifyRegUsed(regNum);
4196     }
4197 }
4198
4199 /*-------------------------------------------------------------------------
4200  *
4201  *  We have to decide whether we're going to use block initialization
4202  *  in the prolog before we assign final stack offsets. This is because
4203  *  when using block initialization we may need additional callee-saved
4204  *  registers which need to be saved on the frame, thus increasing the
4205  *  frame size.
4206  *
4207  *  We'll count the number of locals we have to initialize,
4208  *  and if there are lots of them we'll use block initialization.
4209  *  Thus, the local variable table must have accurate register location
4210  *  information for enregistered locals for their register state on entry
4211  *  to the function.
4212  *
4213  *  At the same time we set lvMustInit for locals (enregistered or on stack)
4214  *  that must be initialized (e.g. initialize memory (comInitMem),
4215  *  untracked pointers or disable DFA)
4216  */
4217 void CodeGen::genCheckUseBlockInit()
4218 {
4219     assert(!compiler->compGeneratingProlog);
4220
4221     unsigned initStkLclCnt = 0; // The number of int-sized stack local variables that need to be initialized (variables
4222                                 // larger than int count for more than 1).
4223
4224     unsigned   varNum;
4225     LclVarDsc* varDsc;
4226
4227     for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
4228     {
4229         // The logic below is complex. Make sure we are not
4230         // double-counting the initialization impact of any locals.
4231         bool counted = false;
4232
4233         if (!varDsc->lvIsInReg() && !varDsc->lvOnFrame)
4234         {
4235             noway_assert(varDsc->lvRefCnt() == 0);
4236             varDsc->lvMustInit = 0;
4237             continue;
4238         }
4239
4240         if (compiler->fgVarIsNeverZeroInitializedInProlog(varNum))
4241         {
4242             varDsc->lvMustInit = 0;
4243             continue;
4244         }
4245
4246         if (compiler->lvaIsFieldOfDependentlyPromotedStruct(varDsc))
4247         {
4248             // For Compiler::PROMOTION_TYPE_DEPENDENT type of promotion, the whole struct should have been
4249             // initialized by the parent struct. No need to set the lvMustInit bit in the
4250             // field locals.
4251             varDsc->lvMustInit = 0;
4252             continue;
4253         }
4254
4255         if (varDsc->lvHasExplicitInit)
4256         {
4257             varDsc->lvMustInit = 0;
4258             continue;
4259         }
4260
4261         const bool isTemp      = varDsc->lvIsTemp;
4262         const bool hasGCPtr    = varDsc->HasGCPtr();
4263         const bool isTracked   = varDsc->lvTracked;
4264         const bool isStruct    = varTypeIsStruct(varDsc);
4265         const bool compInitMem = compiler->info.compInitMem;
4266
4267         if (isTemp && !hasGCPtr)
4268         {
4269             varDsc->lvMustInit = 0;
4270             continue;
4271         }
4272
4273         if (compInitMem || hasGCPtr || varDsc->lvMustInit)
4274         {
4275             if (isTracked)
4276             {
4277                 /* For uninitialized use of tracked variables, the liveness
4278                  * will bubble to the top (compiler->fgFirstBB) in fgInterBlockLocalVarLiveness()
4279                  */
4280                 if (varDsc->lvMustInit ||
4281                     VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
4282                 {
4283                     /* This var must be initialized */
4284
4285                     varDsc->lvMustInit = 1;
4286
4287                     /* See if the variable is on the stack will be initialized
4288                      * using rep stos - compute the total size to be zero-ed */
4289
4290                     if (varDsc->lvOnFrame)
4291                     {
4292                         if (!varDsc->lvRegister)
4293                         {
4294                             if (!varDsc->lvIsInReg() || varDsc->lvLiveInOutOfHndlr)
4295                             {
4296                                 // Var is on the stack at entry.
4297                                 initStkLclCnt +=
4298                                     roundUp(compiler->lvaLclSize(varNum), TARGET_POINTER_SIZE) / sizeof(int);
4299                                 counted = true;
4300                             }
4301                         }
4302                         else
4303                         {
4304                             // Var is partially enregistered
4305                             noway_assert(genTypeSize(varDsc->TypeGet()) > sizeof(int) &&
4306                                          varDsc->GetOtherReg() == REG_STK);
4307                             initStkLclCnt += genTypeStSz(TYP_INT);
4308                             counted = true;
4309                         }
4310                     }
4311                 }
4312             }
4313
4314             if (varDsc->lvOnFrame)
4315             {
4316                 bool mustInitThisVar = false;
4317                 if (hasGCPtr && !isTracked)
4318                 {
4319                     JITDUMP("must init V%02u because it has a GC ref\n", varNum);
4320                     mustInitThisVar = true;
4321                 }
4322                 else if (hasGCPtr && isStruct)
4323                 {
4324                     // TODO-1stClassStructs: support precise liveness reporting for such structs.
4325                     JITDUMP("must init a tracked V%02u because it a struct with a GC ref\n", varNum);
4326                     mustInitThisVar = true;
4327                 }
4328                 else
4329                 {
4330                     // We are done with tracked or GC vars, now look at untracked vars without GC refs.
4331                     if (!isTracked)
4332                     {
4333                         assert(!hasGCPtr && !isTemp);
4334                         if (compInitMem)
4335                         {
4336                             JITDUMP("must init V%02u because compInitMem is set and it is not a temp\n", varNum);
4337                             mustInitThisVar = true;
4338                         }
4339                     }
4340                 }
4341                 if (mustInitThisVar)
4342                 {
4343                     varDsc->lvMustInit = true;
4344
4345                     if (!counted)
4346                     {
4347                         initStkLclCnt += roundUp(compiler->lvaLclSize(varNum), TARGET_POINTER_SIZE) / sizeof(int);
4348                         counted = true;
4349                     }
4350                 }
4351             }
4352         }
4353     }
4354
4355     /* Don't forget about spill temps that hold pointers */
4356     assert(regSet.tmpAllFree());
4357     for (TempDsc* tempThis = regSet.tmpListBeg(); tempThis != nullptr; tempThis = regSet.tmpListNxt(tempThis))
4358     {
4359         if (varTypeIsGC(tempThis->tdTempType()))
4360         {
4361             initStkLclCnt++;
4362         }
4363     }
4364
4365     // Record number of 4 byte slots that need zeroing.
4366     genInitStkLclCnt = initStkLclCnt;
4367
4368     // Decide if we will do block initialization in the prolog, or use
4369     // a series of individual stores.
4370     //
4371     // Primary factor is the number of slots that need zeroing. We've
4372     // been counting by sizeof(int) above. We assume for now we can
4373     // only zero register width bytes per store.
4374     //
4375     // Current heuristic is to use block init when more than 4 stores
4376     // are required.
4377     //
4378     // TODO: Consider taking into account the presence of large structs that
4379     // potentially only need some fields set to zero.
4380     //
4381     // Compiler::fgVarNeedsExplicitZeroInit relies on this logic to
4382     // find structs that are guaranteed to be block initialized.
4383     // If this logic changes, Compiler::fgVarNeedsExplicitZeroInit needs
4384     // to be modified.
4385     CLANG_FORMAT_COMMENT_ANCHOR;
4386
4387 #ifdef TARGET_64BIT
4388 #if defined(TARGET_AMD64)
4389
4390     // We can clear using aligned SIMD so the threshold is lower,
4391     // and clears in order which is better for auto-prefetching
4392     genUseBlockInit = (genInitStkLclCnt > 4);
4393
4394 #else // !defined(TARGET_AMD64)
4395
4396     genUseBlockInit = (genInitStkLclCnt > 8);
4397 #endif
4398 #else
4399
4400     genUseBlockInit = (genInitStkLclCnt > 4);
4401
4402 #endif // TARGET_64BIT
4403
4404     if (genUseBlockInit)
4405     {
4406         regMaskTP maskCalleeRegArgMask = intRegState.rsCalleeRegArgMaskLiveIn;
4407
4408         // If there is a secret stub param, don't count it, as it will no longer
4409         // be live when we do block init.
4410         if (compiler->info.compPublishStubParam)
4411         {
4412             maskCalleeRegArgMask &= ~RBM_SECRET_STUB_PARAM;
4413         }
4414
4415 #ifdef TARGET_ARM
4416         //
4417         // On the Arm if we are using a block init to initialize, then we
4418         // must force spill R4/R5/R6 so that we can use them during
4419         // zero-initialization process.
4420         //
4421         int forceSpillRegCount = genCountBits(maskCalleeRegArgMask & ~regSet.rsMaskPreSpillRegs(false)) - 1;
4422         if (forceSpillRegCount > 0)
4423             regSet.rsSetRegsModified(RBM_R4);
4424         if (forceSpillRegCount > 1)
4425             regSet.rsSetRegsModified(RBM_R5);
4426         if (forceSpillRegCount > 2)
4427             regSet.rsSetRegsModified(RBM_R6);
4428 #endif // TARGET_ARM
4429     }
4430 }
4431
4432 /*****************************************************************************
4433  *
4434  *  initFltRegs -- The mask of float regs to be zeroed.
4435  *  initDblRegs -- The mask of double regs to be zeroed.
4436  *  initReg -- A zero initialized integer reg to copy from.
4437  *
4438  *  Does best effort to move between VFP/xmm regs if one is already
4439  *  initialized to 0. (Arm Only) Else copies from the integer register which
4440  *  is slower.
4441  */
4442 void CodeGen::genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg)
4443 {
4444     assert(compiler->compGeneratingProlog);
4445
4446     // The first float/double reg that is initialized to 0. So they can be used to
4447     // initialize the remaining registers.
4448     regNumber fltInitReg = REG_NA;
4449     regNumber dblInitReg = REG_NA;
4450
4451     // Iterate through float/double registers and initialize them to 0 or
4452     // copy from already initialized register of the same type.
4453     regMaskTP regMask = genRegMask(REG_FP_FIRST);
4454     for (regNumber reg = REG_FP_FIRST; reg <= REG_FP_LAST; reg = REG_NEXT(reg), regMask <<= 1)
4455     {
4456         if (regMask & initFltRegs)
4457         {
4458             // Do we have a float register already set to 0?
4459             if (fltInitReg != REG_NA)
4460             {
4461                 // Copy from float.
4462                 inst_Mov(TYP_FLOAT, reg, fltInitReg, /* canSkip */ false);
4463             }
4464             else
4465             {
4466 #ifdef TARGET_ARM
4467                 // Do we have a double register initialized to 0?
4468                 if (dblInitReg != REG_NA)
4469                 {
4470                     // Copy from double.
4471                     inst_RV_RV(INS_vcvt_d2f, reg, dblInitReg, TYP_FLOAT);
4472                 }
4473                 else
4474                 {
4475                     // Copy from int.
4476                     inst_Mov(TYP_FLOAT, reg, initReg, /* canSkip */ false);
4477                 }
4478 #elif defined(TARGET_XARCH)
4479                 // XORPS is the fastest and smallest way to initialize a XMM register to zero.
4480                 GetEmitter()->emitIns_SIMD_R_R_R(INS_xorps, EA_16BYTE, reg, reg, reg);
4481                 dblInitReg = reg;
4482 #elif defined(TARGET_ARM64)
4483                 // We will just zero out the entire vector register. This sets it to a double/float zero value
4484                 GetEmitter()->emitIns_R_I(INS_movi, EA_16BYTE, reg, 0x00, INS_OPTS_16B);
4485 #elif defined(TARGET_LOONGARCH64)
4486                 // We will just zero out the entire vector register. This sets it to a double/float zero value
4487                 GetEmitter()->emitIns_R_R(INS_movgr2fr_d, EA_8BYTE, reg, REG_R0);
4488 #elif defined(TARGET_RISCV64)
4489                 GetEmitter()->emitIns_R_R(INS_fmv_w_x, EA_4BYTE, reg, REG_R0);
4490 #else // TARGET*
4491 #error Unsupported or unset target architecture
4492 #endif
4493                 fltInitReg = reg;
4494             }
4495         }
4496         else if (regMask & initDblRegs)
4497         {
4498             // Do we have a double register already set to 0?
4499             if (dblInitReg != REG_NA)
4500             {
4501                 // Copy from double.
4502                 inst_Mov(TYP_DOUBLE, reg, dblInitReg, /* canSkip */ false);
4503             }
4504             else
4505             {
4506 #ifdef TARGET_ARM
4507                 // Do we have a float register initialized to 0?
4508                 if (fltInitReg != REG_NA)
4509                 {
4510                     // Copy from float.
4511                     inst_RV_RV(INS_vcvt_f2d, reg, fltInitReg, TYP_DOUBLE);
4512                 }
4513                 else
4514                 {
4515                     // Copy from int.
4516                     inst_RV_RV_RV(INS_vmov_i2d, reg, initReg, initReg, EA_8BYTE);
4517                 }
4518 #elif defined(TARGET_XARCH)
4519                 // XORPS is the fastest and smallest way to initialize a XMM register to zero.
4520                 GetEmitter()->emitIns_SIMD_R_R_R(INS_xorps, EA_16BYTE, reg, reg, reg);
4521                 fltInitReg = reg;
4522 #elif defined(TARGET_ARM64)
4523                 // We will just zero out the entire vector register. This sets it to a double/float zero value
4524                 GetEmitter()->emitIns_R_I(INS_movi, EA_16BYTE, reg, 0x00, INS_OPTS_16B);
4525 #elif defined(TARGET_LOONGARCH64)
4526                 GetEmitter()->emitIns_R_R(INS_movgr2fr_d, EA_8BYTE, reg, REG_R0);
4527 #elif defined(TARGET_RISCV64)
4528                 GetEmitter()->emitIns_R_R(INS_fmv_d_x, EA_8BYTE, reg, REG_R0);
4529 #else // TARGET*
4530 #error Unsupported or unset target architecture
4531 #endif
4532                 dblInitReg = reg;
4533             }
4534         }
4535     }
4536 }
4537
4538 // We need a register with value zero. Zero the initReg, if necessary, and set *pInitRegZeroed if so.
4539 // Return the register to use. On ARM64, we never touch the initReg, and always just return REG_ZR.
4540 regNumber CodeGen::genGetZeroReg(regNumber initReg, bool* pInitRegZeroed)
4541 {
4542 #ifdef TARGET_ARM64
4543     return REG_ZR;
4544 #elif defined(TARGET_LOONGARCH64)
4545     return REG_R0;
4546 #elif defined(TARGET_RISCV64)
4547     return REG_R0;
4548 #else  // !TARGET_ARM64
4549     if (*pInitRegZeroed == false)
4550     {
4551         instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg);
4552         *pInitRegZeroed = true;
4553     }
4554     return initReg;
4555 #endif // !TARGET_ARM64
4556 }
4557
4558 //-----------------------------------------------------------------------------
4559 // genZeroInitFrame: Zero any untracked pointer locals and/or initialize memory for locspace
4560 //
4561 // Arguments:
4562 //    untrLclHi      - (Untracked locals High-Offset)  The upper bound offset at which the zero init
4563 //                                                     code will end initializing memory (not inclusive).
4564 //    untrLclLo      - (Untracked locals Low-Offset)   The lower bound at which the zero init code will
4565 //                                                     start zero initializing memory.
4566 //    initReg        - A scratch register (that gets set to zero on some platforms).
4567 //    pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'true' if this method sets initReg register to zero,
4568 //                     'false' if initReg was set to a non-zero value, and left unchanged if initReg was not touched.
4569 void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed)
4570 {
4571     assert(compiler->compGeneratingProlog);
4572
4573     if (genUseBlockInit)
4574     {
4575         genZeroInitFrameUsingBlockInit(untrLclHi, untrLclLo, initReg, pInitRegZeroed);
4576     }
4577     else if (genInitStkLclCnt > 0)
4578     {
4579         assert((genRegMask(initReg) & intRegState.rsCalleeRegArgMaskLiveIn) == 0); // initReg is not a live incoming
4580                                                                                    // argument reg
4581
4582         /* Initialize any lvMustInit vars on the stack */
4583
4584         LclVarDsc* varDsc;
4585         unsigned   varNum;
4586
4587         for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
4588         {
4589             if (!varDsc->lvMustInit)
4590             {
4591                 continue;
4592             }
4593
4594             // TODO-Review: I'm not sure that we're correctly handling the mustInit case for
4595             // partially-enregistered vars in the case where we don't use a block init.
4596             noway_assert(varDsc->lvIsInReg() || varDsc->lvOnFrame);
4597
4598             // lvMustInit can only be set for GC types or TYP_STRUCT types
4599             // or when compInitMem is true
4600             // or when in debug code
4601
4602             noway_assert(varTypeIsGC(varDsc->TypeGet()) || (varDsc->TypeGet() == TYP_STRUCT) ||
4603                          compiler->info.compInitMem || compiler->opts.compDbgCode);
4604
4605             if (!varDsc->lvOnFrame)
4606             {
4607                 continue;
4608             }
4609
4610             if ((varDsc->TypeGet() == TYP_STRUCT) && !compiler->info.compInitMem &&
4611                 (varDsc->lvExactSize() >= TARGET_POINTER_SIZE))
4612             {
4613                 // We only initialize the GC variables in the TYP_STRUCT
4614                 const unsigned slots  = (unsigned)compiler->lvaLclSize(varNum) / REGSIZE_BYTES;
4615                 ClassLayout*   layout = varDsc->GetLayout();
4616
4617                 for (unsigned i = 0; i < slots; i++)
4618                 {
4619                     if (layout->IsGCPtr(i))
4620                     {
4621                         GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE,
4622                                                   genGetZeroReg(initReg, pInitRegZeroed), varNum, i * REGSIZE_BYTES);
4623                     }
4624                 }
4625             }
4626             else
4627             {
4628                 regNumber zeroReg = genGetZeroReg(initReg, pInitRegZeroed);
4629
4630                 // zero out the whole thing rounded up to a single stack slot size
4631                 unsigned lclSize = roundUp(compiler->lvaLclSize(varNum), (unsigned)sizeof(int));
4632                 unsigned i;
4633                 for (i = 0; i + REGSIZE_BYTES <= lclSize; i += REGSIZE_BYTES)
4634                 {
4635                     GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, zeroReg, varNum, i);
4636                 }
4637
4638 #ifdef TARGET_64BIT
4639                 assert(i == lclSize || (i + sizeof(int) == lclSize));
4640                 if (i != lclSize)
4641                 {
4642                     GetEmitter()->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, zeroReg, varNum, i);
4643                     i += sizeof(int);
4644                 }
4645 #endif // TARGET_64BIT
4646                 assert(i == lclSize);
4647             }
4648         }
4649
4650         assert(regSet.tmpAllFree());
4651         for (TempDsc* tempThis = regSet.tmpListBeg(); tempThis != nullptr; tempThis = regSet.tmpListNxt(tempThis))
4652         {
4653             if (!varTypeIsGC(tempThis->tdTempType()))
4654             {
4655                 continue;
4656             }
4657
4658             // printf("initialize untracked spillTmp [EBP-%04X]\n", stkOffs);
4659
4660             inst_ST_RV(ins_Store(TYP_I_IMPL), tempThis, 0, genGetZeroReg(initReg, pInitRegZeroed), TYP_I_IMPL);
4661         }
4662     }
4663 }
4664
4665 //-----------------------------------------------------------------------------
4666 // genEnregisterOSRArgsAndLocals: Initialize any enregistered args or locals
4667 //   that get values from the tier0 frame.
4668 //
4669 // Arguments:
4670 //    initReg -- scratch register to use if needed
4671 //    pInitRegZeroed -- [IN,OUT] if init reg is zero (on entry/exit)
4672 //
4673 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
4674 void CodeGen::genEnregisterOSRArgsAndLocals(regNumber initReg, bool* pInitRegZeroed)
4675 #else
4676 void CodeGen::genEnregisterOSRArgsAndLocals()
4677 #endif
4678 {
4679     assert(compiler->opts.IsOSR());
4680     PatchpointInfo* const patchpointInfo = compiler->info.compPatchpointInfo;
4681
4682     // basic sanity checks (make sure we're OSRing the right method)
4683     assert(patchpointInfo->NumberOfLocals() == compiler->info.compLocalsCount);
4684
4685     const int      originalFrameSize = patchpointInfo->TotalFrameSize();
4686     const unsigned patchpointInfoLen = patchpointInfo->NumberOfLocals();
4687
4688     for (unsigned varNum = 0; varNum < compiler->lvaCount; varNum++)
4689     {
4690         if (!compiler->lvaIsOSRLocal(varNum))
4691         {
4692             // This local was not part of the tier0 method's state.
4693             // No work required.
4694             //
4695             continue;
4696         }
4697
4698         LclVarDsc* const varDsc = compiler->lvaGetDesc(varNum);
4699
4700         if (!varDsc->lvIsInReg())
4701         {
4702             // For args/locals in memory, the OSR frame will continue to access
4703             // that memory location. No work required.
4704             //
4705             JITDUMP("---OSR--- V%02u in memory\n", varNum);
4706             continue;
4707         }
4708
4709         // This local was part of the live tier0 state and is enregistered in the
4710         // OSR method. Initialize the register from the right frame slot.
4711         //
4712         // If we ever enable promotion we'll need to generalize what follows to copy each
4713         // field from the tier0 frame to its OSR home.
4714         //
4715         if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
4716         {
4717             // This arg or local is not live at entry to the OSR method.
4718             // No work required.
4719             //
4720             JITDUMP("---OSR--- V%02u (reg) not live at entry\n", varNum);
4721             continue;
4722         }
4723
4724         int      fieldOffset = 0;
4725         unsigned lclNum      = varNum;
4726
4727         if (varDsc->lvIsStructField)
4728         {
4729             lclNum = varDsc->lvParentLcl;
4730             assert(lclNum < patchpointInfoLen);
4731
4732             fieldOffset = varDsc->lvFldOffset;
4733             JITDUMP("---OSR--- V%02u is promoted field of V%02u at offset %d\n", varNum, lclNum, fieldOffset);
4734         }
4735
4736         // Note we are always reading from the tier0 frame here
4737         //
4738         const var_types lclTyp  = varDsc->GetStackSlotHomeType();
4739         const emitAttr  size    = emitActualTypeSize(lclTyp);
4740         const int       stkOffs = patchpointInfo->Offset(lclNum) + fieldOffset;
4741
4742 #if defined(TARGET_AMD64)
4743
4744         // Original frames always use frame pointers, so
4745         // stkOffs is the tier0 frame's frame-relative offset
4746         // to the variable.
4747         //
4748         // We need to determine the stack or frame-pointer relative
4749         // offset for this variable in the current frame.
4750         //
4751         // If current frame does not use a frame pointer, we need to
4752         // add the SP-to-FP delta of this frame and the SP-to-FP delta
4753         // of the original frame; that translates from this frame's
4754         // stack pointer the old frame frame pointer.
4755         //
4756         // We then add the original frame's frame-pointer relative
4757         // offset (note this offset is usually negative -- the stack
4758         // grows down, so locals are below the frame pointer).
4759         //
4760         // /-----original frame-----/
4761         // / return address         /
4762         // / saved RBP   --+        /  <--- Original frame ptr   --+
4763         // / ...           |        /                              |
4764         // / ...       (stkOffs)    /                              |
4765         // / ...           |        /                              |
4766         // / variable    --+        /                              |
4767         // / ...                    /                (original frame sp-fp delta)
4768         // / ...                    /                              |
4769         // /-----OSR frame ---------/                              |
4770         // / pseudo return address  /                            --+
4771         // / ...                    /                              |
4772         // / ...                    /                    (this frame sp-fp delta)
4773         // / ...                    /                              |
4774         // /------------------------/  <--- Stack ptr            --+
4775         //
4776         // If the current frame is using a frame pointer, we need to
4777         // add the SP-to-FP delta of/ the original frame and then add
4778         // the original frame's frame-pointer relative offset.
4779         //
4780         // /-----original frame-----/
4781         // / return address         /
4782         // / saved RBP   --+        /  <--- Original frame ptr   --+
4783         // / ...           |        /                              |
4784         // / ...       (stkOffs)    /                              |
4785         // / ...           |        /                              |
4786         // / variable    --+        /                              |
4787         // / ...                    /                (original frame sp-fp delta)
4788         // / ...                    /                              |
4789         // /-----OSR frame ---------/                              |
4790         // / pseudo return address  /                            --+
4791         // / saved RBP              /  <--- Frame ptr            --+
4792         // / ...                    /
4793         // / ...                    /
4794         // / ...                    /
4795         // /------------------------/
4796         //
4797         int offset = originalFrameSize + stkOffs;
4798
4799         if (isFramePointerUsed())
4800         {
4801             // also adjust for saved RPB on this frame
4802             offset += TARGET_POINTER_SIZE;
4803         }
4804         else
4805         {
4806             offset += genSPtoFPdelta();
4807         }
4808
4809         JITDUMP("---OSR--- V%02u (reg) old rbp offset %d old frame %d this frame sp-fp %d new offset %d (0x%02x)\n",
4810                 varNum, stkOffs, originalFrameSize, genSPtoFPdelta(), offset, offset);
4811
4812         GetEmitter()->emitIns_R_AR(ins_Load(lclTyp), size, varDsc->GetRegNum(), genFramePointerReg(), offset);
4813
4814 #elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
4815
4816         // Patchpoint offset is from top of Tier0 frame
4817         //
4818         // We need to determine the frame-pointer relative
4819         // offset for this variable in the osr frame.
4820         //
4821         // First add the Tier0 frame size
4822         //
4823         const int tier0FrameSize = compiler->info.compPatchpointInfo->TotalFrameSize();
4824
4825         // then add the OSR frame size
4826         //
4827         const int osrFrameSize = genTotalFrameSize();
4828
4829         // then subtract OSR SP-FP delta
4830         //
4831         const int osrSpToFpDelta = genSPtoFPdelta();
4832
4833         //               | => tier0 top of frame relative
4834         //               |         + => tier0 bottom of frame relative
4835         //               |         |                + => osr bottom of frame (sp) relative
4836         //               |         |                |              - => osr fp relative
4837         //               |         |                |              |
4838         const int offset = stkOffs + tier0FrameSize + osrFrameSize - osrSpToFpDelta;
4839
4840         JITDUMP("---OSR--- V%02u (reg) Tier0 virtual offset %d OSR frame size %d OSR sp-fp "
4841                 "delta %d total offset %d (0x%x)\n",
4842                 varNum, stkOffs, osrFrameSize, osrSpToFpDelta, offset, offset);
4843
4844         genInstrWithConstant(ins_Load(lclTyp), size, varDsc->GetRegNum(), genFramePointerReg(), offset, initReg);
4845         *pInitRegZeroed = false;
4846 #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
4847     }
4848 }
4849
4850 /*-----------------------------------------------------------------------------
4851  *
4852  *  Save the generic context argument.
4853  *
4854  *  We need to do this within the "prolog" in case anyone tries to inspect
4855  *  the param-type-arg/this (which can be done after the prolog) using
4856  *  ICodeManager::GetParamTypeArg().
4857  */
4858
4859 void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed)
4860 {
4861     assert(compiler->compGeneratingProlog);
4862
4863     const bool reportArg = compiler->lvaReportParamTypeArg();
4864
4865     if (compiler->opts.IsOSR())
4866     {
4867         PatchpointInfo* const ppInfo = compiler->info.compPatchpointInfo;
4868         if (reportArg)
4869         {
4870             // OSR method will use Tier0 slot to report context arg.
4871             //
4872             assert(ppInfo->HasGenericContextArgOffset());
4873             JITDUMP("OSR method will use Tier0 frame slot for generics context arg.\n");
4874         }
4875         else if (compiler->lvaKeepAliveAndReportThis())
4876         {
4877             // OSR method will use Tier0 slot to report `this` as context.
4878             //
4879             assert(ppInfo->HasKeptAliveThis());
4880             JITDUMP("OSR method will use Tier0 frame slot for generics context `this`.\n");
4881         }
4882
4883         return;
4884     }
4885
4886     // We should report either generic context arg or "this" when used so.
4887     if (!reportArg)
4888     {
4889 #ifndef JIT32_GCENCODER
4890         if (!compiler->lvaKeepAliveAndReportThis())
4891 #endif
4892         {
4893             return;
4894         }
4895     }
4896
4897     // For JIT32_GCENCODER, we won't be here if reportArg is false.
4898     unsigned contextArg = reportArg ? compiler->info.compTypeCtxtArg : compiler->info.compThisArg;
4899
4900     noway_assert(contextArg != BAD_VAR_NUM);
4901     LclVarDsc* varDsc = compiler->lvaGetDesc(contextArg);
4902
4903     // We are still in the prolog and compiler->info.compTypeCtxtArg has not been
4904     // moved to its final home location. So we need to use it from the
4905     // incoming location.
4906
4907     regNumber reg;
4908
4909     bool isPrespilledForProfiling = false;
4910 #if defined(TARGET_ARM) && defined(PROFILING_SUPPORTED)
4911     isPrespilledForProfiling =
4912         compiler->compIsProfilerHookNeeded() && compiler->lvaIsPreSpilled(contextArg, regSet.rsMaskPreSpillRegs(false));
4913 #endif
4914
4915     // Load from the argument register only if it is not prespilled.
4916     if (compiler->lvaIsRegArgument(contextArg) && !isPrespilledForProfiling)
4917     {
4918         reg = varDsc->GetArgReg();
4919     }
4920     else
4921     {
4922         if (isFramePointerUsed())
4923         {
4924 #if defined(TARGET_ARM)
4925             // GetStackOffset() is always valid for incoming stack-arguments, even if the argument
4926             // will become enregistered.
4927             // On Arm compiler->compArgSize doesn't include r11 and lr sizes and hence we need to add 2*REGSIZE_BYTES
4928             noway_assert((2 * REGSIZE_BYTES <= varDsc->GetStackOffset()) &&
4929                          (size_t(varDsc->GetStackOffset()) < compiler->compArgSize + 2 * REGSIZE_BYTES));
4930 #else
4931             // GetStackOffset() is always valid for incoming stack-arguments, even if the argument
4932             // will become enregistered.
4933             noway_assert((0 < varDsc->GetStackOffset()) && (size_t(varDsc->GetStackOffset()) < compiler->compArgSize));
4934 #endif
4935         }
4936
4937         // We will just use the initReg since it is an available register
4938         // and we are probably done using it anyway...
4939         reg             = initReg;
4940         *pInitRegZeroed = false;
4941
4942         // mov reg, [compiler->info.compTypeCtxtArg]
4943         GetEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(),
4944                                    varDsc->GetStackOffset());
4945         regSet.verifyRegUsed(reg);
4946     }
4947
4948 #if defined(TARGET_ARM64)
4949     genInstrWithConstant(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(),
4950                          compiler->lvaCachedGenericContextArgOffset(), rsGetRsvdReg());
4951 #elif defined(TARGET_ARM)
4952     // ARM's emitIns_R_R_I automatically uses the reserved register if necessary.
4953     GetEmitter()->emitIns_R_R_I(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(),
4954                                 compiler->lvaCachedGenericContextArgOffset());
4955 #elif defined(TARGET_LOONGARCH64)
4956     genInstrWithConstant(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(),
4957                          compiler->lvaCachedGenericContextArgOffset(), REG_R21);
4958 #elif defined(TARGET_RISCV64)
4959     genInstrWithConstant(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(),
4960                          compiler->lvaCachedGenericContextArgOffset(), rsGetRsvdReg());
4961 #else  // !ARM64 !ARM !LOONGARCH64 !RISCV64
4962     // mov [ebp-lvaCachedGenericContextArgOffset()], reg
4963     GetEmitter()->emitIns_AR_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(),
4964                                compiler->lvaCachedGenericContextArgOffset());
4965 #endif // !ARM64 !ARM !LOONGARCH64 !RISCV64
4966 }
4967
4968 /*****************************************************************************
4969
4970 Esp frames :
4971 ----------
4972
4973 These instructions are just a reordering of the instructions used today.
4974
4975 push ebp
4976 push esi
4977 push edi
4978 push ebx
4979 sub esp, LOCALS_SIZE / push dummyReg if LOCALS_SIZE=sizeof(void*)
4980 ...
4981 add esp, LOCALS_SIZE / pop dummyReg
4982 pop ebx
4983 pop edi
4984 pop esi
4985 pop ebp
4986 ret
4987
4988 Ebp frames :
4989 ----------
4990
4991 The epilog does "add esp, LOCALS_SIZE" instead of "mov ebp, esp".
4992 Everything else is similar, though in a different order.
4993
4994 The security object will no longer be at a fixed offset. However, the
4995 offset can still be determined by looking up the GC-info and determining
4996 how many callee-saved registers are pushed.
4997
4998 push ebp
4999 mov ebp, esp
5000 push esi
5001 push edi
5002 push ebx
5003 sub esp, LOCALS_SIZE / push dummyReg if LOCALS_SIZE=sizeof(void*)
5004 ...
5005 add esp, LOCALS_SIZE / pop dummyReg
5006 pop ebx
5007 pop edi
5008 pop esi
5009 (mov esp, ebp if there are no callee-saved registers)
5010 pop ebp
5011 ret
5012
5013 Double-aligned frame :
5014 --------------------
5015
5016 LOCALS_SIZE_ADJUSTED needs to include an unused DWORD if an odd number
5017 of callee-saved registers are pushed on the stack so that the locals
5018 themselves are qword-aligned. The instructions are the same as today,
5019 just in a different order.
5020
5021 push ebp
5022 mov ebp, esp
5023 and esp, 0xFFFFFFFC
5024 push esi
5025 push edi
5026 push ebx
5027 sub esp, LOCALS_SIZE_ADJUSTED / push dummyReg if LOCALS_SIZE=sizeof(void*)
5028 ...
5029 add esp, LOCALS_SIZE_ADJUSTED / pop dummyReg
5030 pop ebx
5031 pop edi
5032 pop esi
5033 pop ebp
5034 mov esp, ebp
5035 pop ebp
5036 ret
5037
5038 localloc (with ebp) frames :
5039 --------------------------
5040
5041 The instructions are the same as today, just in a different order.
5042 Also, today the epilog does "lea esp, [ebp-LOCALS_SIZE-calleeSavedRegsPushedSize]"
5043 which will change to "lea esp, [ebp-calleeSavedRegsPushedSize]".
5044
5045 push ebp
5046 mov ebp, esp
5047 push esi
5048 push edi
5049 push ebx
5050 sub esp, LOCALS_SIZE / push dummyReg if LOCALS_SIZE=sizeof(void*)
5051 ...
5052 lea esp, [ebp-calleeSavedRegsPushedSize]
5053 pop ebx
5054 pop edi
5055 pop esi
5056 (mov esp, ebp if there are no callee-saved registers)
5057 pop ebp
5058 ret
5059
5060 *****************************************************************************/
5061
5062 /*****************************************************************************
5063  *
5064  *  Reserve space for a function prolog.
5065  */
5066
5067 void CodeGen::genReserveProlog(BasicBlock* block)
5068 {
5069     assert(block != nullptr);
5070
5071     JITDUMP("Reserving prolog IG for block " FMT_BB "\n", block->bbNum);
5072
5073     /* Nothing is live on entry to the prolog */
5074
5075     GetEmitter()->emitCreatePlaceholderIG(IGPT_PROLOG, block, VarSetOps::MakeEmpty(compiler), 0, 0, false);
5076 }
5077
5078 /*****************************************************************************
5079  *
5080  *  Reserve space for a function epilog.
5081  */
5082
5083 void CodeGen::genReserveEpilog(BasicBlock* block)
5084 {
5085     regMaskTP gcrefRegsArg = gcInfo.gcRegGCrefSetCur;
5086     regMaskTP byrefRegsArg = gcInfo.gcRegByrefSetCur;
5087
5088     /* The return value is special-cased: make sure it goes live for the epilog */
5089
5090     bool jmpEpilog = ((block->bbFlags & BBF_HAS_JMP) != 0);
5091
5092     if (IsFullPtrRegMapRequired() && !jmpEpilog)
5093     {
5094         if (varTypeIsGC(compiler->info.compRetNativeType))
5095         {
5096             noway_assert(genTypeStSz(compiler->info.compRetNativeType) == genTypeStSz(TYP_I_IMPL));
5097
5098             gcInfo.gcMarkRegPtrVal(REG_INTRET, compiler->info.compRetNativeType);
5099
5100             switch (compiler->info.compRetNativeType)
5101             {
5102                 case TYP_REF:
5103                     gcrefRegsArg |= RBM_INTRET;
5104                     break;
5105                 case TYP_BYREF:
5106                     byrefRegsArg |= RBM_INTRET;
5107                     break;
5108                 default:
5109                     break;
5110             }
5111
5112             JITDUMP("Extending return value GC liveness to epilog\n");
5113         }
5114     }
5115
5116     JITDUMP("Reserving epilog IG for block " FMT_BB "\n", block->bbNum);
5117
5118     assert(block != nullptr);
5119     const VARSET_TP& gcrefVarsArg(GetEmitter()->emitThisGCrefVars);
5120     bool             last = (block->bbNext == nullptr);
5121     GetEmitter()->emitCreatePlaceholderIG(IGPT_EPILOG, block, gcrefVarsArg, gcrefRegsArg, byrefRegsArg, last);
5122 }
5123
5124 #if defined(FEATURE_EH_FUNCLETS)
5125
5126 /*****************************************************************************
5127  *
5128  *  Reserve space for a funclet prolog.
5129  */
5130
5131 void CodeGen::genReserveFuncletProlog(BasicBlock* block)
5132 {
5133     assert(block != nullptr);
5134
5135     /* Currently, no registers are live on entry to the prolog, except maybe
5136        the exception object. There might be some live stack vars, but they
5137        cannot be accessed until after the frame pointer is re-established.
5138        In order to potentially prevent emitting a death before the prolog
5139        and a birth right after it, we just report it as live during the
5140        prolog, and rely on the prolog being non-interruptible. Trust
5141        genCodeForBBlist to correctly initialize all the sets.
5142
5143        We might need to relax these asserts if the VM ever starts
5144        restoring any registers, then we could have live-in reg vars...
5145     */
5146
5147     noway_assert((gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT) == gcInfo.gcRegGCrefSetCur);
5148     noway_assert(gcInfo.gcRegByrefSetCur == 0);
5149
5150     JITDUMP("Reserving funclet prolog IG for block " FMT_BB "\n", block->bbNum);
5151
5152     GetEmitter()->emitCreatePlaceholderIG(IGPT_FUNCLET_PROLOG, block, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
5153                                           gcInfo.gcRegByrefSetCur, false);
5154 }
5155
5156 /*****************************************************************************
5157  *
5158  *  Reserve space for a funclet epilog.
5159  */
5160
5161 void CodeGen::genReserveFuncletEpilog(BasicBlock* block)
5162 {
5163     assert(block != nullptr);
5164
5165     JITDUMP("Reserving funclet epilog IG for block " FMT_BB "\n", block->bbNum);
5166
5167     bool last = (block->bbNext == nullptr);
5168     GetEmitter()->emitCreatePlaceholderIG(IGPT_FUNCLET_EPILOG, block, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
5169                                           gcInfo.gcRegByrefSetCur, last);
5170 }
5171
5172 #endif // FEATURE_EH_FUNCLETS
5173
5174 /*****************************************************************************
5175  *  Finalize the frame size and offset assignments.
5176  *
5177  *  No changes can be made to the modified register set after this, since that can affect how many
5178  *  callee-saved registers get saved.
5179  */
5180 void CodeGen::genFinalizeFrame()
5181 {
5182     JITDUMP("Finalizing stack frame\n");
5183
5184     // Initializations need to happen based on the var locations at the start
5185     // of the first basic block, so load those up. In particular, the determination
5186     // of whether or not to use block init in the prolog is dependent on the variable
5187     // locations on entry to the function.
5188     compiler->m_pLinearScan->recordVarLocationsAtStartOfBB(compiler->fgFirstBB);
5189
5190     genCheckUseBlockInit();
5191
5192     // Set various registers as "modified" for special code generation scenarios: Edit & Continue, P/Invoke calls, etc.
5193     CLANG_FORMAT_COMMENT_ANCHOR;
5194
5195 #if defined(TARGET_X86)
5196
5197     if (compiler->compTailCallUsed)
5198     {
5199         // If we are generating a helper-based tailcall, we've set the tailcall helper "flags"
5200         // argument to "1", indicating to the tailcall helper that we've saved the callee-saved
5201         // registers (ebx, esi, edi). So, we need to make sure all the callee-saved registers
5202         // actually get saved.
5203
5204         regSet.rsSetRegsModified(RBM_INT_CALLEE_SAVED);
5205     }
5206 #endif // TARGET_X86
5207
5208 #ifdef TARGET_ARM
5209     // Make sure that callee-saved registers used by call to a stack probing helper generated are pushed on stack.
5210     if (compiler->compLclFrameSize >= compiler->eeGetPageSize())
5211     {
5212         regSet.rsSetRegsModified(RBM_STACK_PROBE_HELPER_ARG | RBM_STACK_PROBE_HELPER_CALL_TARGET |
5213                                  RBM_STACK_PROBE_HELPER_TRASH);
5214     }
5215
5216     // If there are any reserved registers, add them to the modified set.
5217     if (regSet.rsMaskResvd != RBM_NONE)
5218     {
5219         regSet.rsSetRegsModified(regSet.rsMaskResvd);
5220     }
5221 #endif // TARGET_ARM
5222
5223 #ifdef DEBUG
5224     if (verbose)
5225     {
5226         printf("Modified regs: ");
5227         dspRegMask(regSet.rsGetModifiedRegsMask());
5228         printf("\n");
5229     }
5230 #endif // DEBUG
5231
5232     // Set various registers as "modified" for special code generation scenarios: Edit & Continue, P/Invoke calls, etc.
5233     if (compiler->opts.compDbgEnC)
5234     {
5235         // We always save FP.
5236         noway_assert(isFramePointerUsed());
5237 #if defined(TARGET_AMD64) || defined(TARGET_ARM64)
5238         regMaskTP okRegs = (RBM_CALLEE_TRASH | RBM_FPBASE | RBM_ENC_CALLEE_SAVED);
5239         if (RBM_ENC_CALLEE_SAVED != 0)
5240         {
5241             regSet.rsSetRegsModified(RBM_ENC_CALLEE_SAVED);
5242         }
5243         noway_assert((regSet.rsGetModifiedRegsMask() & ~okRegs) == 0);
5244 #else  // !TARGET_AMD64 && !TARGET_ARM64
5245         // On x86 we save all callee saved regs so the saved reg area size is consistent
5246         regSet.rsSetRegsModified(RBM_INT_CALLEE_SAVED & ~RBM_FPBASE);
5247 #endif // !TARGET_AMD64 && !TARGET_ARM64
5248     }
5249
5250     /* If we have any pinvoke calls, we might potentially trash everything */
5251     if (compiler->compMethodRequiresPInvokeFrame())
5252     {
5253         noway_assert(isFramePointerUsed()); // Setup of Pinvoke frame currently requires an EBP style frame
5254         regSet.rsSetRegsModified(RBM_INT_CALLEE_SAVED & ~RBM_FPBASE);
5255     }
5256
5257 #ifdef UNIX_AMD64_ABI
5258     // On Unix x64 we also save R14 and R15 for ELT profiler hook generation.
5259     if (compiler->compIsProfilerHookNeeded())
5260     {
5261         regSet.rsSetRegsModified(RBM_PROFILER_ENTER_ARG_0 | RBM_PROFILER_ENTER_ARG_1);
5262     }
5263 #endif
5264
5265     /* Count how many callee-saved registers will actually be saved (pushed) */
5266
5267     // EBP cannot be (directly) modified for EBP frame and double-aligned frames
5268     noway_assert(!doubleAlignOrFramePointerUsed() || !regSet.rsRegsModified(RBM_FPBASE));
5269
5270 #if ETW_EBP_FRAMED
5271     // EBP cannot be (directly) modified
5272     noway_assert(!regSet.rsRegsModified(RBM_FPBASE));
5273 #endif
5274
5275     regMaskTP maskCalleeRegsPushed = regSet.rsGetModifiedRegsMask() & RBM_CALLEE_SAVED;
5276
5277 #ifdef TARGET_ARMARCH
5278     if (isFramePointerUsed())
5279     {
5280         // For a FP based frame we have to push/pop the FP register
5281         //
5282         maskCalleeRegsPushed |= RBM_FPBASE;
5283
5284         // This assert check that we are not using REG_FP
5285         // as both the frame pointer and as a codegen register
5286         //
5287         assert(!regSet.rsRegsModified(RBM_FPBASE));
5288     }
5289
5290     // we always push LR.  See genPushCalleeSavedRegisters
5291     //
5292     maskCalleeRegsPushed |= RBM_LR;
5293
5294 #if defined(TARGET_ARM)
5295     // TODO-ARM64-Bug?: enable some variant of this for FP on ARM64?
5296     regMaskTP maskPushRegsFloat = maskCalleeRegsPushed & RBM_ALLFLOAT;
5297     regMaskTP maskPushRegsInt   = maskCalleeRegsPushed & ~maskPushRegsFloat;
5298
5299     if ((maskPushRegsFloat != RBM_NONE) ||
5300         (compiler->opts.MinOpts() && (regSet.rsMaskResvd & maskCalleeRegsPushed & RBM_OPT_RSVD)))
5301     {
5302         // Here we try to keep stack double-aligned before the vpush
5303         if ((genCountBits(regSet.rsMaskPreSpillRegs(true) | maskPushRegsInt) % 2) != 0)
5304         {
5305             regNumber extraPushedReg = REG_R4;
5306             while (maskPushRegsInt & genRegMask(extraPushedReg))
5307             {
5308                 extraPushedReg = REG_NEXT(extraPushedReg);
5309             }
5310             if (extraPushedReg < REG_R11)
5311             {
5312                 maskPushRegsInt |= genRegMask(extraPushedReg);
5313                 regSet.rsSetRegsModified(genRegMask(extraPushedReg));
5314             }
5315         }
5316         maskCalleeRegsPushed = maskPushRegsInt | maskPushRegsFloat;
5317     }
5318
5319     // We currently only expect to push/pop consecutive FP registers
5320     // and these have to be double-sized registers as well.
5321     // Here we will insure that maskPushRegsFloat obeys these requirements.
5322     //
5323     if (maskPushRegsFloat != RBM_NONE)
5324     {
5325         regMaskTP contiguousMask = genRegMaskFloat(REG_F16);
5326         while (maskPushRegsFloat > contiguousMask)
5327         {
5328             contiguousMask <<= 2;
5329             contiguousMask |= genRegMaskFloat(REG_F16);
5330         }
5331         if (maskPushRegsFloat != contiguousMask)
5332         {
5333             regMaskTP maskExtraRegs = contiguousMask - maskPushRegsFloat;
5334             maskPushRegsFloat |= maskExtraRegs;
5335             regSet.rsSetRegsModified(maskExtraRegs);
5336             maskCalleeRegsPushed |= maskExtraRegs;
5337         }
5338     }
5339 #endif // TARGET_ARM
5340 #endif // TARGET_ARMARCH
5341
5342 #if defined(TARGET_XARCH)
5343     // Compute the count of callee saved float regs saved on stack.
5344     // On Amd64 we push only integer regs. Callee saved float (xmm6-xmm31)
5345     // regs are stack allocated and preserved in their stack locations.
5346     compiler->compCalleeFPRegsSavedMask = maskCalleeRegsPushed & RBM_FLT_CALLEE_SAVED;
5347     maskCalleeRegsPushed &= ~RBM_FLT_CALLEE_SAVED;
5348 #endif // defined(TARGET_XARCH)
5349
5350 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
5351     if (isFramePointerUsed())
5352     {
5353         // For a FP based frame we have to push/pop the FP register
5354         //
5355         maskCalleeRegsPushed |= RBM_FPBASE;
5356
5357         // This assert check that we are not using REG_FP
5358         // as both the frame pointer and as a codegen register
5359         //
5360         assert(!regSet.rsRegsModified(RBM_FPBASE));
5361     }
5362
5363     // we always push RA.  See genPushCalleeSavedRegisters
5364     maskCalleeRegsPushed |= RBM_RA;
5365 #endif // TARGET_LOONGARCH64 || TARGET_RISCV64
5366
5367     compiler->compCalleeRegsPushed = genCountBits(maskCalleeRegsPushed);
5368
5369 #ifdef DEBUG
5370     if (verbose)
5371     {
5372         printf("Callee-saved registers pushed: %d ", compiler->compCalleeRegsPushed);
5373         dspRegMask(maskCalleeRegsPushed);
5374         printf("\n");
5375     }
5376 #endif // DEBUG
5377
5378     /* Assign the final offsets to things living on the stack frame */
5379
5380     compiler->lvaAssignFrameOffsets(Compiler::FINAL_FRAME_LAYOUT);
5381
5382 #ifdef DEBUG
5383     if (compiler->opts.dspCode || compiler->opts.disAsm || compiler->opts.disAsm2 || verbose)
5384     {
5385         compiler->lvaTableDump();
5386     }
5387 #endif
5388 }
5389
5390 /*****************************************************************************
5391  *
5392  *  Generates code for a function prolog.
5393  *
5394  *  NOTE REGARDING CHANGES THAT IMPACT THE DEBUGGER:
5395  *
5396  *  The debugger relies on decoding ARM instructions to be able to successfully step through code. It does not
5397  *  implement decoding all ARM instructions. It only implements decoding the instructions which the JIT emits, and
5398  *  only instructions which result in control not going to the next instruction. Basically, any time execution would
5399  *  not continue at the next instruction (such as B, BL, BX, BLX, POP{pc}, etc.), the debugger has to be able to
5400  *  decode that instruction. If any of this is changed on ARM, the debugger team needs to be notified so that it
5401  *  can ensure stepping isn't broken. This is also a requirement for x86 and amd64.
5402  *
5403  *  If any changes are made in the prolog, epilog, calls, returns, and branches, it is a good idea to notify the
5404  *  debugger team to ensure that stepping still works.
5405  *
5406  *  ARM stepping code is here: debug\ee\arm\armwalker.cpp, vm\arm\armsinglestepper.cpp.
5407  */
5408
5409 #ifdef _PREFAST_
5410 #pragma warning(push)
5411 #pragma warning(disable : 21000) // Suppress PREFast warning about overly large function
5412 #endif
5413 void CodeGen::genFnProlog()
5414 {
5415     ScopedSetVariable<bool> _setGeneratingProlog(&compiler->compGeneratingProlog, true);
5416
5417     compiler->funSetCurrentFunc(0);
5418
5419 #ifdef DEBUG
5420     if (verbose)
5421     {
5422         printf("*************** In genFnProlog()\n");
5423     }
5424 #endif
5425
5426 #ifdef DEBUG
5427     genInterruptibleUsed = true;
5428 #endif
5429
5430     assert(compiler->lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT);
5431
5432     /* Ready to start on the prolog proper */
5433
5434     GetEmitter()->emitBegProlog();
5435     compiler->unwindBegProlog();
5436
5437     // Do this so we can put the prolog instruction group ahead of
5438     // other instruction groups
5439     genIPmappingAddToFront(IPmappingDscKind::Prolog, DebugInfo(), true);
5440
5441 #ifdef DEBUG
5442     if (compiler->opts.dspCode)
5443     {
5444         printf("\n__prolog:\n");
5445     }
5446 #endif
5447
5448     if (compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0))
5449     {
5450         // Create new scopes for the method-parameters for the prolog-block.
5451         psiBegProlog();
5452     }
5453
5454 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
5455     // For arm64 OSR, emit a "phantom prolog" to account for the actions taken
5456     // in the tier0 frame that impact FP and SP on entry to the OSR method.
5457     //
5458     // x64 handles this differently; the phantom prolog unwind is emitted in
5459     // genOSRRecordTier0CalleeSavedRegistersAndFrame.
5460     //
5461     if (compiler->opts.IsOSR())
5462     {
5463         PatchpointInfo* patchpointInfo = compiler->info.compPatchpointInfo;
5464         const int       tier0FrameSize = patchpointInfo->TotalFrameSize();
5465
5466         // SP is tier0 method's SP.
5467         compiler->unwindAllocStack(tier0FrameSize);
5468     }
5469 #endif // defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
5470
5471 #ifdef DEBUG
5472
5473     if (compiler->compJitHaltMethod())
5474     {
5475         /* put a nop first because the debugger and other tools are likely to
5476            put an int3 at the beginning and we don't want to confuse them */
5477
5478         instGen(INS_nop);
5479         instGen(INS_BREAKPOINT);
5480
5481 #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
5482         // Avoid asserts in the unwind info because these instructions aren't accounted for.
5483         compiler->unwindPadding();
5484 #endif // TARGET_ARMARCH || TARGET_LOONGARCH64 || TARGET_RISCV64
5485     }
5486 #endif // DEBUG
5487
5488 #if defined(FEATURE_EH_FUNCLETS) && defined(DEBUG)
5489
5490     // We cannot force 0-initialization of the PSPSym
5491     // as it will overwrite the real value
5492     if (compiler->lvaPSPSym != BAD_VAR_NUM)
5493     {
5494         const LclVarDsc* varDsc = compiler->lvaGetDesc(compiler->lvaPSPSym);
5495         assert(!varDsc->lvMustInit);
5496     }
5497
5498 #endif // FEATURE_EH_FUNCLETS && DEBUG
5499
5500     /*-------------------------------------------------------------------------
5501      *
5502      *  Record the stack frame ranges that will cover all of the tracked
5503      *  and untracked pointer variables.
5504      *  Also find which registers will need to be zero-initialized.
5505      *
5506      *  'initRegs': - Generally, enregistered variables should not need to be
5507      *                zero-inited. They only need to be zero-inited when they
5508      *                have a possibly uninitialized read on some control
5509      *                flow path. Apparently some of the IL_STUBs that we
5510      *                generate have this property.
5511      */
5512
5513     int untrLclLo = +INT_MAX;
5514     int untrLclHi = -INT_MAX;
5515     // 'hasUntrLcl' is true if there are any stack locals which must be init'ed.
5516     // Note that they may be tracked, but simply not allocated to a register.
5517     bool hasUntrLcl = false;
5518
5519     int  GCrefLo  = +INT_MAX;
5520     int  GCrefHi  = -INT_MAX;
5521     bool hasGCRef = false;
5522
5523     regMaskTP initRegs    = RBM_NONE; // Registers which must be init'ed.
5524     regMaskTP initFltRegs = RBM_NONE; // FP registers which must be init'ed.
5525     regMaskTP initDblRegs = RBM_NONE;
5526
5527     unsigned   varNum;
5528     LclVarDsc* varDsc;
5529
5530     for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
5531     {
5532         if (varDsc->lvIsParam && !varDsc->lvIsRegArg)
5533         {
5534             continue;
5535         }
5536
5537         if (!varDsc->lvIsInReg() && !varDsc->lvOnFrame)
5538         {
5539             noway_assert(varDsc->lvRefCnt() == 0);
5540             continue;
5541         }
5542
5543         signed int loOffs = varDsc->GetStackOffset();
5544         signed int hiOffs = varDsc->GetStackOffset() + compiler->lvaLclSize(varNum);
5545
5546         /* We need to know the offset range of tracked stack GC refs */
5547         /* We assume that the GC reference can be anywhere in the TYP_STRUCT */
5548
5549         if (varDsc->HasGCPtr() && varDsc->lvTrackedNonStruct() && varDsc->lvOnFrame)
5550         {
5551             // For fields of PROMOTION_TYPE_DEPENDENT type of promotion, they should have been
5552             // taken care of by the parent struct.
5553             if (!compiler->lvaIsFieldOfDependentlyPromotedStruct(varDsc))
5554             {
5555                 hasGCRef = true;
5556
5557                 if (loOffs < GCrefLo)
5558                 {
5559                     GCrefLo = loOffs;
5560                 }
5561                 if (hiOffs > GCrefHi)
5562                 {
5563                     GCrefHi = hiOffs;
5564                 }
5565             }
5566         }
5567
5568         /* For lvMustInit vars, gather pertinent info */
5569
5570         if (!varDsc->lvMustInit)
5571         {
5572             continue;
5573         }
5574
5575         bool isInReg    = varDsc->lvIsInReg();
5576         bool isInMemory = !isInReg || varDsc->lvLiveInOutOfHndlr;
5577
5578         // Note that 'lvIsInReg()' will only be accurate for variables that are actually live-in to
5579         // the first block. This will include all possibly-uninitialized locals, whose liveness
5580         // will naturally propagate up to the entry block. However, we also set 'lvMustInit' for
5581         // locals that are live-in to a finally block, and those may not be live-in to the first
5582         // block. For those, we don't want to initialize the register, as it will not actually be
5583         // occupying it on entry.
5584         if (isInReg)
5585         {
5586             if (compiler->lvaEnregEHVars && varDsc->lvLiveInOutOfHndlr)
5587             {
5588                 isInReg = VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex);
5589             }
5590             else
5591             {
5592                 assert(VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex));
5593             }
5594         }
5595
5596         if (isInReg)
5597         {
5598             regNumber regForVar = varDsc->GetRegNum();
5599             regMaskTP regMask   = genRegMask(regForVar);
5600             if (!genIsValidFloatReg(regForVar))
5601             {
5602                 initRegs |= regMask;
5603
5604                 if (varTypeIsMultiReg(varDsc))
5605                 {
5606                     if (varDsc->GetOtherReg() != REG_STK)
5607                     {
5608                         initRegs |= genRegMask(varDsc->GetOtherReg());
5609                     }
5610                     else
5611                     {
5612                         /* Upper DWORD is on the stack, and needs to be inited */
5613
5614                         loOffs += sizeof(int);
5615                         goto INIT_STK;
5616                     }
5617                 }
5618             }
5619             else if (varDsc->TypeGet() == TYP_DOUBLE)
5620             {
5621                 initDblRegs |= regMask;
5622             }
5623             else
5624             {
5625                 initFltRegs |= regMask;
5626             }
5627         }
5628         if (isInMemory)
5629         {
5630         INIT_STK:
5631
5632             hasUntrLcl = true;
5633
5634             if (loOffs < untrLclLo)
5635             {
5636                 untrLclLo = loOffs;
5637             }
5638             if (hiOffs > untrLclHi)
5639             {
5640                 untrLclHi = hiOffs;
5641             }
5642         }
5643     }
5644
5645     /* Don't forget about spill temps that hold pointers */
5646
5647     assert(regSet.tmpAllFree());
5648     for (TempDsc* tempThis = regSet.tmpListBeg(); tempThis != nullptr; tempThis = regSet.tmpListNxt(tempThis))
5649     {
5650         if (!varTypeIsGC(tempThis->tdTempType()))
5651         {
5652             continue;
5653         }
5654
5655         signed int loOffs = tempThis->tdTempOffs();
5656         signed int hiOffs = loOffs + TARGET_POINTER_SIZE;
5657
5658         // If there is a frame pointer used, due to frame pointer chaining it will point to the stored value of the
5659         // previous frame pointer. Thus, stkOffs can't be zero.
5660         CLANG_FORMAT_COMMENT_ANCHOR;
5661
5662 #if !defined(TARGET_AMD64)
5663         // However, on amd64 there is no requirement to chain frame pointers.
5664
5665         noway_assert(!isFramePointerUsed() || loOffs != 0);
5666 #endif // !defined(TARGET_AMD64)
5667
5668         // printf("    Untracked tmp at [EBP-%04X]\n", -stkOffs);
5669
5670         hasUntrLcl = true;
5671
5672         if (loOffs < untrLclLo)
5673         {
5674             untrLclLo = loOffs;
5675         }
5676         if (hiOffs > untrLclHi)
5677         {
5678             untrLclHi = hiOffs;
5679         }
5680     }
5681
5682     // TODO-Cleanup: Add suitable assert for the OSR case.
5683     assert(compiler->opts.IsOSR() || ((genInitStkLclCnt > 0) == hasUntrLcl));
5684
5685 #ifdef DEBUG
5686     if (verbose)
5687     {
5688         if (genInitStkLclCnt > 0)
5689         {
5690             printf("Found %u lvMustInit int-sized stack slots, frame offsets %d through %d\n", genInitStkLclCnt,
5691                    -untrLclLo, -untrLclHi);
5692         }
5693     }
5694 #endif
5695
5696 #ifdef TARGET_ARM
5697     // On the ARM we will spill any incoming struct args in the first instruction in the prolog
5698     // Ditto for all enregistered user arguments in a varargs method.
5699     // These registers will be available to use for the initReg.  We just remove
5700     // all of these registers from the rsCalleeRegArgMaskLiveIn.
5701     //
5702     intRegState.rsCalleeRegArgMaskLiveIn &= ~regSet.rsMaskPreSpillRegs(false);
5703 #endif
5704
5705     /* Choose the register to use for zero initialization */
5706
5707     regNumber initReg = REG_SCRATCH; // Unless we find a better register below
5708
5709     // Track if initReg holds non-zero value. Start conservative and assume it has non-zero value.
5710     // If initReg is ever set to zero, this variable is set to true and zero initializing initReg
5711     // will be skipped.
5712     bool      initRegZeroed = false;
5713     regMaskTP excludeMask   = intRegState.rsCalleeRegArgMaskLiveIn;
5714     regMaskTP tempMask;
5715
5716     // We should not use the special PINVOKE registers as the initReg
5717     // since they are trashed by the jithelper call to setup the PINVOKE frame
5718     if (compiler->compMethodRequiresPInvokeFrame())
5719     {
5720         excludeMask |= RBM_PINVOKE_FRAME;
5721
5722         assert((!compiler->opts.ShouldUsePInvokeHelpers()) || (compiler->info.compLvFrameListRoot == BAD_VAR_NUM));
5723         if (!compiler->opts.ShouldUsePInvokeHelpers())
5724         {
5725             excludeMask |= (RBM_PINVOKE_TCB | RBM_PINVOKE_SCRATCH);
5726
5727             // We also must exclude the register used by compLvFrameListRoot when it is enregistered
5728             //
5729             const LclVarDsc* varDsc = compiler->lvaGetDesc(compiler->info.compLvFrameListRoot);
5730             if (varDsc->lvRegister)
5731             {
5732                 excludeMask |= genRegMask(varDsc->GetRegNum());
5733             }
5734         }
5735     }
5736
5737 #ifdef TARGET_ARM
5738     // If we have a variable sized frame (compLocallocUsed is true)
5739     // then using REG_SAVED_LOCALLOC_SP in the prolog is not allowed
5740     if (compiler->compLocallocUsed)
5741     {
5742         excludeMask |= RBM_SAVED_LOCALLOC_SP;
5743     }
5744 #endif // TARGET_ARM
5745
5746     const bool isRoot = (compiler->funCurrentFunc()->funKind == FuncKind::FUNC_ROOT);
5747
5748 #ifdef TARGET_AMD64
5749     const bool isOSRx64Root = isRoot && compiler->opts.IsOSR();
5750 #else
5751     const bool isOSRx64Root = false;
5752 #endif // TARGET_AMD64
5753
5754     tempMask = initRegs & ~excludeMask & ~regSet.rsMaskResvd;
5755
5756     if (tempMask != RBM_NONE)
5757     {
5758         // We will use one of the registers that we were planning to zero init anyway.
5759         // We pick the lowest register number.
5760         tempMask = genFindLowestBit(tempMask);
5761         initReg  = genRegNumFromMask(tempMask);
5762     }
5763     // Next we prefer to use one of the unused argument registers.
5764     // If they aren't available we use one of the caller-saved integer registers.
5765     else
5766     {
5767         tempMask = regSet.rsGetModifiedRegsMask() & RBM_ALLINT & ~excludeMask & ~regSet.rsMaskResvd;
5768         if (tempMask != RBM_NONE)
5769         {
5770             // We pick the lowest register number
5771             tempMask = genFindLowestBit(tempMask);
5772             initReg  = genRegNumFromMask(tempMask);
5773         }
5774     }
5775
5776 #if defined(TARGET_AMD64)
5777     // For x64 OSR root frames, we can't use any as of yet unsaved
5778     // callee save as initReg, as we defer saving these until later in
5779     // the prolog, and we don't have normal arg regs.
5780     if (isOSRx64Root)
5781     {
5782         initReg = REG_SCRATCH; // REG_EAX
5783     }
5784 #elif defined(TARGET_ARM64)
5785     // For arm64 OSR root frames, we may need a scratch register for large
5786     // offset addresses. Use a register that won't be allocated.
5787     //
5788     if (isRoot && compiler->opts.IsOSR())
5789     {
5790         initReg = REG_IP1;
5791     }
5792 #elif defined(TARGET_RISCV64)
5793     // For RISC-V64 OSR root frames, we may need a scratch register for large
5794     // offset addresses. Use a register that won't be allocated.
5795     if (isRoot && compiler->opts.IsOSR())
5796     {
5797         initReg = REG_SCRATCH; // REG_T0
5798     }
5799 #endif
5800
5801 #if !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
5802     // For LoongArch64's OSR root frames, we may need a scratch register for large
5803     // offset addresses. But this does not conflict with the REG_PINVOKE_FRAME.
5804     //
5805     // RISC-V64's OSR root frames are similar to LoongArch64's. In this case
5806     // REG_SCRATCH also shouldn't conflict with REG_PINVOKE_FRAME, even if
5807     // technically they are the same register - REG_T0.
5808     //
5809     noway_assert(!compiler->compMethodRequiresPInvokeFrame() || (initReg != REG_PINVOKE_FRAME));
5810 #endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64
5811
5812 #if defined(TARGET_AMD64)
5813     // If we are a varargs call, in order to set up the arguments correctly this
5814     // must be done in a 2 step process. As per the x64 ABI:
5815     // a) The caller sets up the argument shadow space (just before the return
5816     //    address, 4 pointer sized slots).
5817     // b) The callee is responsible to home the arguments on the shadow space
5818     //    provided by the caller.
5819     // This way, the varargs iterator will be able to retrieve the
5820     // call arguments properly since both the arg regs and the stack allocated
5821     // args will be contiguous.
5822     //
5823     // OSR methods can skip this, as the setup is done by the original method.
5824     if (compiler->info.compIsVarArgs && !compiler->opts.IsOSR())
5825     {
5826         GetEmitter()->spillIntArgRegsToShadowSlots();
5827     }
5828
5829 #endif // TARGET_AMD64
5830
5831 #ifdef TARGET_ARM
5832     /*-------------------------------------------------------------------------
5833      *
5834      * Now start emitting the part of the prolog which sets up the frame
5835      */
5836
5837     if (regSet.rsMaskPreSpillRegs(true) != RBM_NONE)
5838     {
5839         inst_IV(INS_push, (int)regSet.rsMaskPreSpillRegs(true));
5840         compiler->unwindPushMaskInt(regSet.rsMaskPreSpillRegs(true));
5841     }
5842 #endif // TARGET_ARM
5843
5844     unsigned extraFrameSize = 0;
5845
5846 #ifdef TARGET_XARCH
5847
5848 #ifdef TARGET_AMD64
5849     if (isOSRx64Root)
5850     {
5851         // Account for the Tier0 callee saves
5852         //
5853         genOSRRecordTier0CalleeSavedRegistersAndFrame();
5854
5855         // We don't actually push any callee saves on the OSR frame,
5856         // but we still reserve space, so account for this when
5857         // allocating the local frame.
5858         //
5859         extraFrameSize = compiler->compCalleeRegsPushed * REGSIZE_BYTES;
5860     }
5861 #endif // TARGET_AMD64
5862
5863     if (doubleAlignOrFramePointerUsed())
5864     {
5865         // OSR methods handle "saving" FP specially.
5866         //
5867         // For epilog and unwind, we restore the RBP saved by the
5868         // Tier0 method. The save we do here is just to set up a
5869         // proper RBP-based frame chain link.
5870         //
5871         if (isOSRx64Root && isFramePointerUsed())
5872         {
5873             GetEmitter()->emitIns_R_AR(INS_mov, EA_8BYTE, initReg, REG_FPBASE, 0);
5874             inst_RV(INS_push, initReg, TYP_REF);
5875             initRegZeroed = false;
5876
5877             // We account for the SP movement in unwind, but not for
5878             // the "save" of RBP.
5879             //
5880             compiler->unwindAllocStack(REGSIZE_BYTES);
5881         }
5882         else
5883         {
5884             inst_RV(INS_push, REG_FPBASE, TYP_REF);
5885             compiler->unwindPush(REG_FPBASE);
5886         }
5887 #ifndef TARGET_AMD64 // On AMD64, establish the frame pointer after the "sub rsp"
5888         genEstablishFramePointer(0, /*reportUnwindData*/ true);
5889 #endif // !TARGET_AMD64
5890
5891 #if DOUBLE_ALIGN
5892         if (compiler->genDoubleAlign())
5893         {
5894             noway_assert(isFramePointerUsed() == false);
5895             noway_assert(!regSet.rsRegsModified(RBM_FPBASE)); /* Trashing EBP is out.    */
5896
5897             inst_RV_IV(INS_AND, REG_SPBASE, -8, EA_PTRSIZE);
5898         }
5899 #endif // DOUBLE_ALIGN
5900     }
5901 #endif // TARGET_XARCH
5902
5903 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
5904     genPushCalleeSavedRegisters(initReg, &initRegZeroed);
5905
5906 #else  // !TARGET_ARM64 && !TARGET_LOONGARCH64 && !TARGET_RISCV64
5907
5908     if (!isOSRx64Root)
5909     {
5910         genPushCalleeSavedRegisters();
5911     }
5912 #endif // !TARGET_ARM64 && !TARGET_LOONGARCH64 && !TARGET_RISCV64
5913
5914 #ifdef TARGET_ARM
5915     bool needToEstablishFP        = false;
5916     int  afterLclFrameSPtoFPdelta = 0;
5917     if (doubleAlignOrFramePointerUsed())
5918     {
5919         needToEstablishFP = true;
5920
5921         // If the local frame is small enough, we establish the frame pointer after the OS-reported prolog.
5922         // This makes the prolog and epilog match, giving us smaller unwind data. If the frame size is
5923         // too big, we go ahead and do it here.
5924
5925         int SPtoFPdelta          = (compiler->compCalleeRegsPushed - 2) * REGSIZE_BYTES;
5926         afterLclFrameSPtoFPdelta = SPtoFPdelta + compiler->compLclFrameSize;
5927         if (!arm_Valid_Imm_For_Add_SP(afterLclFrameSPtoFPdelta))
5928         {
5929             // Oh well, it looks too big. Go ahead and establish the frame pointer here.
5930             genEstablishFramePointer(SPtoFPdelta, /*reportUnwindData*/ true);
5931             needToEstablishFP = false;
5932         }
5933     }
5934 #endif // TARGET_ARM
5935
5936     //-------------------------------------------------------------------------
5937     //
5938     // Subtract the local frame size from SP.
5939     //
5940     //-------------------------------------------------------------------------
5941     CLANG_FORMAT_COMMENT_ANCHOR;
5942
5943 #if !defined(TARGET_ARM64) && !defined(TARGET_LOONGARCH64) && !defined(TARGET_RISCV64)
5944     regMaskTP maskStackAlloc = RBM_NONE;
5945
5946 #ifdef TARGET_ARM
5947     maskStackAlloc = genStackAllocRegisterMask(compiler->compLclFrameSize + extraFrameSize,
5948                                                regSet.rsGetModifiedRegsMask() & RBM_FLT_CALLEE_SAVED);
5949 #endif // TARGET_ARM
5950
5951     if (maskStackAlloc == RBM_NONE)
5952     {
5953         genAllocLclFrame(compiler->compLclFrameSize + extraFrameSize, initReg, &initRegZeroed,
5954                          intRegState.rsCalleeRegArgMaskLiveIn);
5955     }
5956 #endif // !TARGET_ARM64 && !TARGET_LOONGARCH64 && !TARGET_RISCV64
5957
5958 #ifdef TARGET_AMD64
5959     // For x64 OSR we have to finish saving int callee saves.
5960     //
5961     if (isOSRx64Root)
5962     {
5963         genOSRSaveRemainingCalleeSavedRegisters();
5964     }
5965 #endif // TARGET_AMD64
5966
5967 //-------------------------------------------------------------------------
5968
5969 #ifdef TARGET_ARM
5970     if (compiler->compLocallocUsed)
5971     {
5972         GetEmitter()->emitIns_Mov(INS_mov, EA_4BYTE, REG_SAVED_LOCALLOC_SP, REG_SPBASE, /* canSkip */ false);
5973         regSet.verifyRegUsed(REG_SAVED_LOCALLOC_SP);
5974         compiler->unwindSetFrameReg(REG_SAVED_LOCALLOC_SP, 0);
5975     }
5976 #endif // TARGET_ARMARCH
5977
5978 #if defined(TARGET_XARCH)
5979     // Preserve callee saved float regs to stack.
5980     genPreserveCalleeSavedFltRegs(compiler->compLclFrameSize);
5981 #endif // defined(TARGET_XARCH)
5982
5983 #ifdef TARGET_AMD64
5984     // Establish the AMD64 frame pointer after the OS-reported prolog.
5985     if (doubleAlignOrFramePointerUsed())
5986     {
5987         const bool reportUnwindData = compiler->compLocallocUsed || compiler->opts.compDbgEnC;
5988         genEstablishFramePointer(compiler->codeGen->genSPtoFPdelta(), reportUnwindData);
5989     }
5990 #endif // TARGET_AMD64
5991     compiler->unwindEndProlog();
5992
5993 //-------------------------------------------------------------------------
5994 //
5995 // This is the end of the OS-reported prolog for purposes of unwinding
5996 //
5997 //-------------------------------------------------------------------------
5998
5999 #ifdef TARGET_ARM
6000     if (needToEstablishFP)
6001     {
6002         genEstablishFramePointer(afterLclFrameSPtoFPdelta, /*reportUnwindData*/ false);
6003         needToEstablishFP = false; // nobody uses this later, but set it anyway, just to be explicit
6004     }
6005 #endif // TARGET_ARM
6006
6007     if (compiler->info.compPublishStubParam)
6008     {
6009         GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SECRET_STUB_PARAM,
6010                                   compiler->lvaStubArgumentVar, 0);
6011         assert(intRegState.rsCalleeRegArgMaskLiveIn & RBM_SECRET_STUB_PARAM);
6012
6013         // It's no longer live; clear it out so it can be used after this in the prolog
6014         intRegState.rsCalleeRegArgMaskLiveIn &= ~RBM_SECRET_STUB_PARAM;
6015     }
6016
6017     //
6018     // Zero out the frame as needed
6019     //
6020
6021     genZeroInitFrame(untrLclHi, untrLclLo, initReg, &initRegZeroed);
6022
6023 #if defined(FEATURE_EH_FUNCLETS)
6024
6025     genSetPSPSym(initReg, &initRegZeroed);
6026
6027 #else // !FEATURE_EH_FUNCLETS
6028
6029     // when compInitMem is true the genZeroInitFrame will zero out the shadow SP slots
6030     if (compiler->ehNeedsShadowSPslots() && !compiler->info.compInitMem)
6031     {
6032         // The last slot is reserved for ICodeManager::FixContext(ppEndRegion)
6033         unsigned filterEndOffsetSlotOffs = compiler->lvaLclSize(compiler->lvaShadowSPslotsVar) - TARGET_POINTER_SIZE;
6034
6035         // Zero out the slot for nesting level 0
6036         unsigned firstSlotOffs = filterEndOffsetSlotOffs - TARGET_POINTER_SIZE;
6037
6038         if (!initRegZeroed)
6039         {
6040             instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg);
6041             initRegZeroed = true;
6042         }
6043
6044         GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, initReg, compiler->lvaShadowSPslotsVar,
6045                                   firstSlotOffs);
6046     }
6047
6048 #endif // !FEATURE_EH_FUNCLETS
6049
6050     genReportGenericContextArg(initReg, &initRegZeroed);
6051
6052 #ifdef JIT32_GCENCODER
6053     // Initialize the LocalAllocSP slot if there is localloc in the function.
6054     if (compiler->lvaLocAllocSPvar != BAD_VAR_NUM)
6055     {
6056         GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE, compiler->lvaLocAllocSPvar, 0);
6057     }
6058 #endif // JIT32_GCENCODER
6059
6060     // Set up the GS security cookie
6061
6062     genSetGSSecurityCookie(initReg, &initRegZeroed);
6063
6064 #ifdef PROFILING_SUPPORTED
6065
6066     // Insert a function entry callback for profiling, if requested.
6067     // OSR methods aren't called, so don't have enter hooks.
6068     if (!compiler->opts.IsOSR())
6069     {
6070         genProfilingEnterCallback(initReg, &initRegZeroed);
6071     }
6072
6073 #endif // PROFILING_SUPPORTED
6074
6075     // For OSR we may have a zero-length prolog. That's not supported
6076     // when the method must report a generics context,/ so add a nop if so.
6077     //
6078     if (compiler->opts.IsOSR() && (GetEmitter()->emitGetPrologOffsetEstimate() == 0) &&
6079         (compiler->lvaReportParamTypeArg() || compiler->lvaKeepAliveAndReportThis()))
6080     {
6081         JITDUMP("OSR: prolog was zero length and has generic context to report: adding nop to pad prolog.\n");
6082         instGen(INS_nop);
6083     }
6084
6085     if (!GetInterruptible())
6086     {
6087         // The 'real' prolog ends here for non-interruptible methods.
6088         // For fully-interruptible methods, we extend the prolog so that
6089         // we do not need to track GC information while shuffling the
6090         // arguments.
6091         GetEmitter()->emitMarkPrologEnd();
6092     }
6093
6094 #if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
6095     // The unused bits of Vector3 arguments must be cleared
6096     // since native compiler doesn't initize the upper bits to zeros.
6097     //
6098     // TODO-Cleanup: This logic can be implemented in
6099     // genFnPrologCalleeRegArgs() for argument registers and
6100     // genEnregisterIncomingStackArgs() for stack arguments.
6101     genClearStackVec3ArgUpperBits();
6102 #endif // UNIX_AMD64_ABI && FEATURE_SIMD
6103
6104     /*-----------------------------------------------------------------------------
6105      * Take care of register arguments first
6106      */
6107
6108     // Home incoming arguments and generate any required inits.
6109     // OSR handles this by moving the values from the original frame.
6110     //
6111     // Update the arg initial register locations.
6112     //
6113     if (compiler->opts.IsOSR())
6114     {
6115         // For OSR  we defer updating "initial reg" for args until
6116         // we've set the live-in regs with values from the Tier0 frame.
6117         //
6118         // Otherwise we'll do some of these fetches twice.
6119         //
6120         CLANG_FORMAT_COMMENT_ANCHOR;
6121 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
6122         genEnregisterOSRArgsAndLocals(initReg, &initRegZeroed);
6123 #else
6124         genEnregisterOSRArgsAndLocals();
6125 #endif
6126         compiler->lvaUpdateArgsWithInitialReg();
6127     }
6128     else
6129     {
6130         compiler->lvaUpdateArgsWithInitialReg();
6131
6132 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
6133         if (intRegState.rsCalleeRegArgMaskLiveIn || floatRegState.rsCalleeRegArgMaskLiveIn)
6134         {
6135             initRegZeroed = false;
6136             genFnPrologCalleeRegArgs();
6137         }
6138 #else
6139         auto assignIncomingRegisterArgs = [this, initReg, &initRegZeroed](RegState* regState) {
6140             if (regState->rsCalleeRegArgMaskLiveIn)
6141             {
6142                 // If we need an extra register to shuffle around the incoming registers
6143                 // we will use xtraReg (initReg) and set the xtraRegClobbered flag,
6144                 // if we don't need to use the xtraReg then this flag will stay false
6145                 //
6146                 regNumber xtraReg;
6147                 bool      xtraRegClobbered = false;
6148
6149                 if (genRegMask(initReg) & RBM_ARG_REGS)
6150                 {
6151                     xtraReg = initReg;
6152                 }
6153                 else
6154                 {
6155                     xtraReg       = REG_SCRATCH;
6156                     initRegZeroed = false;
6157                 }
6158
6159                 genFnPrologCalleeRegArgs(xtraReg, &xtraRegClobbered, regState);
6160
6161                 if (xtraRegClobbered)
6162                 {
6163                     initRegZeroed = false;
6164                 }
6165             }
6166         };
6167
6168 #if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM)
6169         assignIncomingRegisterArgs(&intRegState);
6170         assignIncomingRegisterArgs(&floatRegState);
6171 #else
6172         assignIncomingRegisterArgs(&intRegState);
6173 #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
6174
6175 #endif // TARGET_LOONGARCH64 || TARGET_RISCV64
6176
6177         // Home the incoming arguments.
6178         genEnregisterIncomingStackArgs();
6179     }
6180
6181     /* Initialize any must-init registers variables now */
6182
6183     if (initRegs)
6184     {
6185         regMaskTP regMask = 0x1;
6186
6187         for (regNumber reg = REG_INT_FIRST; reg <= REG_INT_LAST; reg = REG_NEXT(reg), regMask <<= 1)
6188         {
6189             if (regMask & initRegs)
6190             {
6191                 // Check if we have already zeroed this register
6192                 if ((reg == initReg) && initRegZeroed)
6193                 {
6194                     continue;
6195                 }
6196                 else
6197                 {
6198                     instGen_Set_Reg_To_Zero(EA_PTRSIZE, reg);
6199                     if (reg == initReg)
6200                     {
6201                         initRegZeroed = true;
6202                     }
6203                 }
6204             }
6205         }
6206     }
6207
6208     if (initFltRegs | initDblRegs)
6209     {
6210         // If initReg is not in initRegs then we will use REG_SCRATCH
6211         if ((genRegMask(initReg) & initRegs) == 0)
6212         {
6213             initReg       = REG_SCRATCH;
6214             initRegZeroed = false;
6215         }
6216
6217 #ifdef TARGET_ARM
6218         // This is needed only for Arm since it can use a zero initialized int register
6219         // to initialize vfp registers.
6220         if (!initRegZeroed)
6221         {
6222             instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg);
6223             initRegZeroed = true;
6224         }
6225 #endif // TARGET_ARM
6226
6227         genZeroInitFltRegs(initFltRegs, initDblRegs, initReg);
6228     }
6229
6230     //-----------------------------------------------------------------------------
6231
6232     //
6233     // Increase the prolog size here only if fully interruptible.
6234     //
6235
6236     if (GetInterruptible())
6237     {
6238         GetEmitter()->emitMarkPrologEnd();
6239     }
6240     if (compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0))
6241     {
6242         psiEndProlog();
6243     }
6244
6245     if (hasGCRef)
6246     {
6247         GetEmitter()->emitSetFrameRangeGCRs(GCrefLo, GCrefHi);
6248     }
6249     else
6250     {
6251         noway_assert(GCrefLo == +INT_MAX);
6252         noway_assert(GCrefHi == -INT_MAX);
6253     }
6254
6255 #ifdef DEBUG
6256     if (compiler->opts.dspCode)
6257     {
6258         printf("\n");
6259     }
6260 #endif
6261
6262 #ifdef TARGET_X86
6263     // On non-x86 the VARARG cookie does not need any special treatment.
6264
6265     // Load up the VARARG argument pointer register so it doesn't get clobbered.
6266     // only do this if we actually access any statically declared args
6267     // (our argument pointer register has a refcount > 0).
6268     unsigned argsStartVar = compiler->lvaVarargsBaseOfStkArgs;
6269
6270     if (compiler->info.compIsVarArgs && compiler->lvaGetDesc(argsStartVar)->lvRefCnt() > 0)
6271     {
6272         varDsc = compiler->lvaGetDesc(argsStartVar);
6273
6274         noway_assert(compiler->info.compArgsCount > 0);
6275
6276         // MOV EAX, <VARARGS HANDLE>
6277         GetEmitter()->emitIns_R_S(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_EAX, compiler->info.compArgsCount - 1, 0);
6278         regSet.verifyRegUsed(REG_EAX);
6279
6280         // MOV EAX, [EAX]
6281         GetEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_EAX, REG_EAX, 0);
6282
6283         // EDX might actually be holding something here.  So make sure to only use EAX for this code
6284         // sequence.
6285
6286         const LclVarDsc* lastArg = compiler->lvaGetDesc(compiler->info.compArgsCount - 1);
6287         noway_assert(!lastArg->lvRegister);
6288         signed offset = lastArg->GetStackOffset();
6289         assert(offset != BAD_STK_OFFS);
6290         noway_assert(lastArg->lvFramePointerBased);
6291
6292         // LEA EAX, &<VARARGS HANDLE> + EAX
6293         GetEmitter()->emitIns_R_ARR(INS_lea, EA_PTRSIZE, REG_EAX, genFramePointerReg(), REG_EAX, offset);
6294
6295         if (varDsc->lvIsInReg())
6296         {
6297             GetEmitter()->emitIns_Mov(INS_mov, EA_PTRSIZE, varDsc->GetRegNum(), REG_EAX, /* canSkip */ true);
6298             regSet.verifyRegUsed(varDsc->GetRegNum());
6299         }
6300         else
6301         {
6302             GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_EAX, argsStartVar, 0);
6303         }
6304     }
6305
6306 #endif // TARGET_X86
6307
6308 #if defined(DEBUG) && defined(TARGET_XARCH)
6309     if (compiler->opts.compStackCheckOnRet)
6310     {
6311         assert(compiler->lvaReturnSpCheck != BAD_VAR_NUM);
6312         assert(compiler->lvaGetDesc(compiler->lvaReturnSpCheck)->lvDoNotEnregister);
6313         assert(compiler->lvaGetDesc(compiler->lvaReturnSpCheck)->lvOnFrame);
6314         GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, REG_SPBASE, compiler->lvaReturnSpCheck, 0);
6315     }
6316 #endif // defined(DEBUG) && defined(TARGET_XARCH)
6317
6318     GetEmitter()->emitEndProlog();
6319 }
6320 #ifdef _PREFAST_
6321 #pragma warning(pop)
6322 #endif
6323
6324 //------------------------------------------------------------------------
6325 // getCallTarget - Get the node that evaluates to the call target
6326 //
6327 // Arguments:
6328 //    call - the GT_CALL node
6329 //
6330 // Returns:
6331 //   The node. Note that for direct calls this may still return non-null if the direct call
6332 //   requires a 'complex' tree to load the target (e.g. in R2R or because we go through a stub).
6333 //
6334 GenTree* CodeGen::getCallTarget(const GenTreeCall* call, CORINFO_METHOD_HANDLE* methHnd)
6335 {
6336     // all virtuals should have been expanded into a control expression by this point.
6337     assert(!call->IsVirtual() || call->gtControlExpr || call->gtCallAddr);
6338
6339     if (call->gtCallType == CT_INDIRECT)
6340     {
6341         assert(call->gtControlExpr == nullptr);
6342
6343         if (methHnd != nullptr)
6344         {
6345             *methHnd = nullptr;
6346         }
6347
6348         return call->gtCallAddr;
6349     }
6350
6351     if (methHnd != nullptr)
6352     {
6353         *methHnd = call->gtCallMethHnd;
6354     }
6355
6356     return call->gtControlExpr;
6357 }
6358
6359 //------------------------------------------------------------------------
6360 // getCallIndirectionCellReg - Get the register containing the indirection cell for a call
6361 //
6362 // Arguments:
6363 //    call - the node
6364 //
6365 // Returns:
6366 //   The register containing the indirection cell, or REG_NA if this call does not use an indirection cell argument.
6367 //
6368 // Notes:
6369 //   We currently use indirection cells for VSD on all platforms and for R2R calls on ARM architectures.
6370 //
6371 regNumber CodeGen::getCallIndirectionCellReg(GenTreeCall* call)
6372 {
6373     regNumber result = REG_NA;
6374     switch (call->GetIndirectionCellArgKind())
6375     {
6376         case WellKnownArg::None:
6377             break;
6378         case WellKnownArg::R2RIndirectionCell:
6379             result = REG_R2R_INDIRECT_PARAM;
6380             break;
6381         case WellKnownArg::VirtualStubCell:
6382             result = compiler->virtualStubParamInfo->GetReg();
6383             break;
6384         default:
6385             unreached();
6386     }
6387
6388 #ifdef DEBUG
6389     if (call->GetIndirectionCellArgKind() != WellKnownArg::None)
6390     {
6391         CallArg* indirCellArg = call->gtArgs.FindWellKnownArg(call->GetIndirectionCellArgKind());
6392         assert((indirCellArg != nullptr) && (indirCellArg->AbiInfo.GetRegNum() == result));
6393     }
6394 #endif
6395
6396     return result;
6397 }
6398
6399 //------------------------------------------------------------------------
6400 // genDefinePendingLabel - If necessary, define the pending call label after a
6401 // call instruction was emitted.
6402 //
6403 // Arguments:
6404 //    call - the call node
6405 //
6406 void CodeGen::genDefinePendingCallLabel(GenTreeCall* call)
6407 {
6408     // for pinvoke/intrinsic/tailcalls we may have needed to get the address of
6409     // a label.
6410     if (!genPendingCallLabel)
6411     {
6412         return;
6413     }
6414
6415     // For certain indirect calls we may introduce helper calls before that we need to skip:
6416     // - CFG may introduce a call to the validator first
6417     // - Generic virtual methods may compute the target dynamically through a separate helper call
6418     if (call->IsHelperCall(compiler, CORINFO_HELP_VALIDATE_INDIRECT_CALL) ||
6419         call->IsHelperCall(compiler, CORINFO_HELP_VIRTUAL_FUNC_PTR))
6420     {
6421         return;
6422     }
6423
6424     genDefineInlineTempLabel(genPendingCallLabel);
6425     genPendingCallLabel = nullptr;
6426 }
6427
6428 /*****************************************************************************
6429  *
6430  *  Generates code for all the function and funclet prologs and epilogs.
6431  */
6432
6433 void CodeGen::genGeneratePrologsAndEpilogs()
6434 {
6435 #ifdef DEBUG
6436     if (verbose)
6437     {
6438         printf("*************** Before prolog / epilog generation\n");
6439         GetEmitter()->emitDispIGlist(/* displayInstructions */ false);
6440     }
6441 #endif
6442
6443     // Before generating the prolog, we need to reset the variable locations to what they will be on entry.
6444     // This affects our code that determines which untracked locals need to be zero initialized.
6445     compiler->m_pLinearScan->recordVarLocationsAtStartOfBB(compiler->fgFirstBB);
6446
6447     // Tell the emitter we're done with main code generation, and are going to start prolog and epilog generation.
6448
6449     GetEmitter()->emitStartPrologEpilogGeneration();
6450
6451     gcInfo.gcResetForBB();
6452     genFnProlog();
6453
6454     // Generate all the prologs and epilogs.
6455     CLANG_FORMAT_COMMENT_ANCHOR;
6456
6457 #if defined(FEATURE_EH_FUNCLETS)
6458
6459     // Capture the data we're going to use in the funclet prolog and epilog generation. This is
6460     // information computed during codegen, or during function prolog generation, like
6461     // frame offsets. It must run after main function prolog generation.
6462
6463     genCaptureFuncletPrologEpilogInfo();
6464
6465 #endif // FEATURE_EH_FUNCLETS
6466
6467     // Walk the list of prologs and epilogs and generate them.
6468     // We maintain a list of prolog and epilog basic blocks in
6469     // the insGroup structure in the emitter. This list was created
6470     // during code generation by the genReserve*() functions.
6471     //
6472     // TODO: it seems like better design would be to create a list of prologs/epilogs
6473     // in the code generator (not the emitter), and then walk that list. But we already
6474     // have the insGroup list, which serves well, so we don't need the extra allocations
6475     // for a prolog/epilog list in the code generator.
6476
6477     GetEmitter()->emitGeneratePrologEpilog();
6478
6479     // Tell the emitter we're done with all prolog and epilog generation.
6480
6481     GetEmitter()->emitFinishPrologEpilogGeneration();
6482
6483 #ifdef DEBUG
6484     if (verbose)
6485     {
6486         printf("*************** After prolog / epilog generation\n");
6487         GetEmitter()->emitDispIGlist(/* displayInstructions */ false);
6488     }
6489 #endif
6490 }
6491
6492 /*
6493 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6494 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6495 XX                                                                           XX
6496 XX                           End Prolog / Epilog                             XX
6497 XX                                                                           XX
6498 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6499 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6500 */
6501
6502 //-----------------------------------------------------------------------------------
6503 // IsMultiRegReturnedType: Returns true if the type is returned in multiple registers
6504 //
6505 // Arguments:
6506 //     hClass   -  type handle
6507 //
6508 // Return Value:
6509 //     true if type is returned in multiple registers, false otherwise.
6510 //
6511 bool Compiler::IsMultiRegReturnedType(CORINFO_CLASS_HANDLE hClass, CorInfoCallConvExtension callConv)
6512 {
6513     if (hClass == NO_CLASS_HANDLE)
6514     {
6515         return false;
6516     }
6517
6518     structPassingKind howToReturnStruct;
6519     var_types         returnType = getReturnTypeForStruct(hClass, callConv, &howToReturnStruct);
6520
6521 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
6522     return (varTypeIsStruct(returnType) && (howToReturnStruct != SPK_PrimitiveType));
6523 #else
6524     return (varTypeIsStruct(returnType));
6525 #endif
6526 }
6527
6528 //----------------------------------------------
6529 // Methods that support HFA's for ARM32/ARM64
6530 //----------------------------------------------
6531
6532 bool Compiler::IsHfa(CORINFO_CLASS_HANDLE hClass)
6533 {
6534     return varTypeIsValidHfaType(GetHfaType(hClass));
6535 }
6536
6537 var_types Compiler::GetHfaType(CORINFO_CLASS_HANDLE hClass)
6538 {
6539     if (GlobalJitOptions::compFeatureHfa)
6540     {
6541         if (hClass != NO_CLASS_HANDLE)
6542         {
6543             CorInfoHFAElemType elemKind = info.compCompHnd->getHFAType(hClass);
6544             if (elemKind != CORINFO_HFA_ELEM_NONE)
6545             {
6546                 // This type may not appear elsewhere, but it will occupy a floating point register.
6547                 compFloatingPointUsed = true;
6548             }
6549             return HfaTypeFromElemKind(elemKind);
6550         }
6551     }
6552     return TYP_UNDEF;
6553 }
6554
6555 //------------------------------------------------------------------------
6556 // GetHfaCount: Given a  class handle for an HFA struct
6557 //    return the number of registers needed to hold the HFA
6558 //
6559 //    Note that on ARM32 the single precision registers overlap with
6560 //        the double precision registers and for that reason each
6561 //        double register is considered to be two single registers.
6562 //        Thus for ARM32 an HFA of 4 doubles this function will return 8.
6563 //    On ARM64 given an HFA of 4 singles or 4 doubles this function will
6564 //         will return 4 for both.
6565 // Arguments:
6566 //    hClass: the class handle of a HFA struct
6567 //
6568 unsigned Compiler::GetHfaCount(CORINFO_CLASS_HANDLE hClass)
6569 {
6570     assert(IsHfa(hClass));
6571 #ifdef TARGET_ARM
6572     // A HFA of doubles is twice as large as an HFA of singles for ARM32
6573     // (i.e. uses twice the number of single precision registers)
6574     return info.compCompHnd->getClassSize(hClass) / REGSIZE_BYTES;
6575 #else  // TARGET_ARM64
6576     var_types hfaType   = GetHfaType(hClass);
6577     unsigned  classSize = info.compCompHnd->getClassSize(hClass);
6578     // Note that the retail build issues a warning about a potential division by zero without the Max function
6579     unsigned elemSize = Max((unsigned)1, EA_SIZE_IN_BYTES(emitActualTypeSize(hfaType)));
6580     return classSize / elemSize;
6581 #endif // TARGET_ARM64
6582 }
6583
6584 //------------------------------------------------------------------------------------------------ //
6585 // getFirstArgWithStackSlot - returns the first argument with stack slot on the caller's frame.
6586 //
6587 // Return value:
6588 //    The number of the first argument with stack slot on the caller's frame.
6589 //
6590 // Note:
6591 //    On x64 Windows the caller always creates slots (homing space) in its frame for the
6592 //    first 4 arguments of a callee (register passed args). So, the variable number
6593 //    (lclNum) for the first argument with a stack slot is always 0.
6594 //    For System V systems or armarch, there is no such calling convention requirement, and the code
6595 //    needs to find the first stack passed argument from the caller. This is done by iterating over
6596 //    all the lvParam variables and finding the first with GetArgReg() equals to REG_STK.
6597 //
6598 unsigned CodeGen::getFirstArgWithStackSlot()
6599 {
6600 #if defined(UNIX_AMD64_ABI) || defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
6601     unsigned baseVarNum = 0;
6602     // Iterate over all the lvParam variables in the Lcl var table until we find the first one
6603     // that's passed on the stack.
6604     LclVarDsc* varDsc = nullptr;
6605     for (unsigned i = 0; i < compiler->info.compArgsCount; i++)
6606     {
6607         varDsc = compiler->lvaGetDesc(i);
6608
6609         // We should have found a stack parameter (and broken out of this loop) before
6610         // we find any non-parameters.
6611         assert(varDsc->lvIsParam);
6612
6613         if (varDsc->GetArgReg() == REG_STK)
6614         {
6615             baseVarNum = i;
6616             break;
6617         }
6618     }
6619     assert(varDsc != nullptr);
6620
6621     return baseVarNum;
6622 #elif defined(TARGET_AMD64)
6623     return 0;
6624 #else  // TARGET_X86
6625     // Not implemented for x86.
6626     NYI_X86("getFirstArgWithStackSlot not yet implemented for x86.");
6627     return BAD_VAR_NUM;
6628 #endif // TARGET_X86
6629 }
6630
6631 //------------------------------------------------------------------------
6632 // genSinglePush: Report a change in stack level caused by a single word-sized push instruction
6633 //
6634 void CodeGen::genSinglePush()
6635 {
6636     AddStackLevel(REGSIZE_BYTES);
6637 }
6638
6639 //------------------------------------------------------------------------
6640 // genSinglePop: Report a change in stack level caused by a single word-sized pop instruction
6641 //
6642 void CodeGen::genSinglePop()
6643 {
6644     SubtractStackLevel(REGSIZE_BYTES);
6645 }
6646
6647 //------------------------------------------------------------------------
6648 // genPushRegs: Push the given registers.
6649 //
6650 // Arguments:
6651 //    regs - mask or registers to push
6652 //    byrefRegs - OUT arg. Set to byref registers that were pushed.
6653 //    noRefRegs - OUT arg. Set to non-GC ref registers that were pushed.
6654 //
6655 // Return Value:
6656 //    Mask of registers pushed.
6657 //
6658 // Notes:
6659 //    This function does not check if the register is marked as used, etc.
6660 //
6661 regMaskTP CodeGen::genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs)
6662 {
6663     *byrefRegs = RBM_NONE;
6664     *noRefRegs = RBM_NONE;
6665
6666     if (regs == RBM_NONE)
6667     {
6668         return RBM_NONE;
6669     }
6670
6671 #if FEATURE_FIXED_OUT_ARGS
6672
6673     NYI("Don't call genPushRegs with real regs!");
6674     return RBM_NONE;
6675
6676 #else // FEATURE_FIXED_OUT_ARGS
6677
6678     noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_I_IMPL));
6679     noway_assert(genTypeStSz(TYP_BYREF) == genTypeStSz(TYP_I_IMPL));
6680
6681     regMaskTP pushedRegs = regs;
6682
6683     for (regNumber reg = REG_INT_FIRST; regs != RBM_NONE; reg = REG_NEXT(reg))
6684     {
6685         regMaskTP regBit = regMaskTP(1) << reg;
6686
6687         if ((regBit & regs) == RBM_NONE)
6688             continue;
6689
6690         var_types type;
6691         if (regBit & gcInfo.gcRegGCrefSetCur)
6692         {
6693             type = TYP_REF;
6694         }
6695         else if (regBit & gcInfo.gcRegByrefSetCur)
6696         {
6697             *byrefRegs |= regBit;
6698             type = TYP_BYREF;
6699         }
6700         else if (noRefRegs != NULL)
6701         {
6702             *noRefRegs |= regBit;
6703             type = TYP_I_IMPL;
6704         }
6705         else
6706         {
6707             continue;
6708         }
6709
6710         inst_RV(INS_push, reg, type);
6711
6712         genSinglePush();
6713         gcInfo.gcMarkRegSetNpt(regBit);
6714
6715         regs &= ~regBit;
6716     }
6717
6718     return pushedRegs;
6719
6720 #endif // FEATURE_FIXED_OUT_ARGS
6721 }
6722
6723 //------------------------------------------------------------------------
6724 // genPopRegs: Pop the registers that were pushed by genPushRegs().
6725 //
6726 // Arguments:
6727 //    regs - mask of registers to pop
6728 //    byrefRegs - The byref registers that were pushed by genPushRegs().
6729 //    noRefRegs - The non-GC ref registers that were pushed by genPushRegs().
6730 //
6731 // Return Value:
6732 //    None
6733 //
6734 void CodeGen::genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs)
6735 {
6736     if (regs == RBM_NONE)
6737     {
6738         return;
6739     }
6740
6741 #if FEATURE_FIXED_OUT_ARGS
6742
6743     NYI("Don't call genPopRegs with real regs!");
6744
6745 #else // FEATURE_FIXED_OUT_ARGS
6746
6747     noway_assert((regs & byrefRegs) == byrefRegs);
6748     noway_assert((regs & noRefRegs) == noRefRegs);
6749     noway_assert((regs & (gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur)) == RBM_NONE);
6750
6751     noway_assert(genTypeStSz(TYP_REF) == genTypeStSz(TYP_INT));
6752     noway_assert(genTypeStSz(TYP_BYREF) == genTypeStSz(TYP_INT));
6753
6754     // Walk the registers in the reverse order as genPushRegs()
6755     for (regNumber reg = REG_INT_LAST; regs != RBM_NONE; reg = REG_PREV(reg))
6756     {
6757         regMaskTP regBit = regMaskTP(1) << reg;
6758
6759         if ((regBit & regs) == RBM_NONE)
6760             continue;
6761
6762         var_types type;
6763         if (regBit & byrefRegs)
6764         {
6765             type = TYP_BYREF;
6766         }
6767         else if (regBit & noRefRegs)
6768         {
6769             type = TYP_INT;
6770         }
6771         else
6772         {
6773             type = TYP_REF;
6774         }
6775
6776         inst_RV(INS_pop, reg, type);
6777         genSinglePop();
6778
6779         if (type != TYP_INT)
6780             gcInfo.gcMarkRegPtrVal(reg, type);
6781
6782         regs &= ~regBit;
6783     }
6784
6785 #endif // FEATURE_FIXED_OUT_ARGS
6786 }
6787
6788 /*****************************************************************************
6789  *                          genSetScopeInfo
6790  *
6791  * This function should be called only after the sizes of the emitter blocks
6792  * have been finalized.
6793  */
6794
6795 void CodeGen::genSetScopeInfo()
6796 {
6797     if (!compiler->opts.compScopeInfo)
6798     {
6799         return;
6800     }
6801
6802 #ifdef DEBUG
6803     if (verbose)
6804     {
6805         printf("*************** In genSetScopeInfo()\n");
6806     }
6807 #endif
6808
6809     unsigned varsLocationsCount = 0;
6810
6811     varsLocationsCount = (unsigned int)varLiveKeeper->getLiveRangesCount();
6812
6813     if (varsLocationsCount == 0)
6814     {
6815         // No variable home to report
6816         compiler->eeSetLVcount(0);
6817         compiler->eeSetLVdone();
6818         return;
6819     }
6820
6821     noway_assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
6822
6823     // Initialize the table where the reported variables' home will be placed.
6824     compiler->eeSetLVcount(varsLocationsCount);
6825
6826 #ifdef DEBUG
6827     genTrnslLocalVarCount = varsLocationsCount;
6828     if (varsLocationsCount)
6829     {
6830         genTrnslLocalVarInfo = new (compiler, CMK_DebugOnly) TrnslLocalVarInfo[varsLocationsCount];
6831     }
6832 #endif
6833
6834     // We can have one of both flags defined, both, or none. Specially if we need to compare both
6835     // both results. But we cannot report both to the debugger, since there would be overlapping
6836     // intervals, and may not indicate the same variable location.
6837
6838     genSetScopeInfoUsingVariableRanges();
6839
6840     compiler->eeSetLVdone();
6841 }
6842
6843 //------------------------------------------------------------------------
6844 // genSetScopeInfoUsingVariableRanges: Call "genSetScopeInfo" with the
6845 //  "VariableLiveRanges" created for the arguments, special arguments and
6846 //  IL local variables.
6847 //
6848 // Notes:
6849 //  This function is called from "genSetScopeInfo" once the code is generated
6850 //  and we want to send debug info to the debugger.
6851 //
6852 void CodeGen::genSetScopeInfoUsingVariableRanges()
6853 {
6854     unsigned int liveRangeIndex = 0;
6855
6856     for (unsigned int varNum = 0; varNum < compiler->info.compLocalsCount; varNum++)
6857     {
6858         LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);
6859
6860         if (compiler->compMap2ILvarNum(varNum) == (unsigned int)ICorDebugInfo::UNKNOWN_ILNUM)
6861         {
6862             continue;
6863         }
6864
6865         auto reportRange = [this, varDsc, varNum, &liveRangeIndex](siVarLoc* loc, UNATIVE_OFFSET start,
6866                                                                    UNATIVE_OFFSET end) {
6867             if (varDsc->lvIsParam && (start == end))
6868             {
6869                 // If the length is zero, it means that the prolog is empty. In that case,
6870                 // CodeGen::genSetScopeInfo will report the liveness of all arguments
6871                 // as spanning the first instruction in the method, so that they can
6872                 // at least be inspected on entry to the method.
6873                 end++;
6874             }
6875
6876             if (start < end)
6877             {
6878                 genSetScopeInfo(liveRangeIndex, start, end - start, varNum, varNum, true, loc);
6879                 liveRangeIndex++;
6880             }
6881         };
6882
6883         siVarLoc*      curLoc   = nullptr;
6884         UNATIVE_OFFSET curStart = 0;
6885         UNATIVE_OFFSET curEnd   = 0;
6886
6887         for (int rangeIndex = 0; rangeIndex < 2; rangeIndex++)
6888         {
6889             VariableLiveKeeper::LiveRangeList* liveRanges;
6890             if (rangeIndex == 0)
6891             {
6892                 liveRanges = varLiveKeeper->getLiveRangesForVarForProlog(varNum);
6893             }
6894             else
6895             {
6896                 liveRanges = varLiveKeeper->getLiveRangesForVarForBody(varNum);
6897             }
6898
6899             for (VariableLiveKeeper::VariableLiveRange& liveRange : *liveRanges)
6900             {
6901                 UNATIVE_OFFSET startOffs = liveRange.m_StartEmitLocation.CodeOffset(GetEmitter());
6902                 UNATIVE_OFFSET endOffs   = liveRange.m_EndEmitLocation.CodeOffset(GetEmitter());
6903
6904                 assert(startOffs <= endOffs);
6905                 assert(startOffs >= curEnd);
6906                 if ((curLoc != nullptr) && (startOffs == curEnd) && siVarLoc::Equals(curLoc, &liveRange.m_VarLocation))
6907                 {
6908                     // Extend current range.
6909                     curEnd = endOffs;
6910                     continue;
6911                 }
6912
6913                 // Report old range if any.
6914                 if (curLoc != nullptr)
6915                 {
6916                     reportRange(curLoc, curStart, curEnd);
6917                 }
6918
6919                 // Start a new range.
6920                 curLoc   = &liveRange.m_VarLocation;
6921                 curStart = startOffs;
6922                 curEnd   = endOffs;
6923             }
6924         }
6925
6926         // Report last range
6927         if (curLoc != nullptr)
6928         {
6929             reportRange(curLoc, curStart, curEnd);
6930         }
6931     }
6932
6933     compiler->eeVarsCount = liveRangeIndex;
6934 }
6935
6936 //------------------------------------------------------------------------
6937 // genSetScopeInfo: Record scope information for debug info
6938 //
6939 // Arguments:
6940 //    which
6941 //    startOffs - the starting offset for this scope
6942 //    length    - the length of this scope
6943 //    varNum    - the lclVar for this scope info
6944 //    LVnum
6945 //    avail     - a bool indicating if it has a home
6946 //    varLoc    - the position (reg or stack) of the variable
6947 //
6948 // Notes:
6949 //    Called for every scope info piece to record by the main genSetScopeInfo()
6950
6951 void CodeGen::genSetScopeInfo(unsigned       which,
6952                               UNATIVE_OFFSET startOffs,
6953                               UNATIVE_OFFSET length,
6954                               unsigned       varNum,
6955                               unsigned       LVnum,
6956                               bool           avail,
6957                               siVarLoc*      varLoc)
6958 {
6959     // We need to do some mapping while reporting back these variables.
6960
6961     unsigned ilVarNum = compiler->compMap2ILvarNum(varNum);
6962     noway_assert((int)ilVarNum != ICorDebugInfo::UNKNOWN_ILNUM);
6963
6964 #ifdef TARGET_X86
6965     // Non-x86 platforms are allowed to access all arguments directly
6966     // so we don't need this code.
6967
6968     // Is this a varargs function?
6969     if (compiler->info.compIsVarArgs && varNum != compiler->lvaVarargsHandleArg &&
6970         varNum < compiler->info.compArgsCount && !compiler->lvaGetDesc(varNum)->lvIsRegArg)
6971     {
6972         noway_assert(varLoc->vlType == VLT_STK || varLoc->vlType == VLT_STK2);
6973
6974         // All stack arguments (except the varargs handle) have to be
6975         // accessed via the varargs cookie. Discard generated info,
6976         // and just find its position relative to the varargs handle
6977
6978         PREFIX_ASSUME(compiler->lvaVarargsHandleArg < compiler->info.compArgsCount);
6979         if (!compiler->lvaGetDesc(compiler->lvaVarargsHandleArg)->lvOnFrame)
6980         {
6981             noway_assert(!compiler->opts.compDbgCode);
6982             return;
6983         }
6984
6985         // Can't check compiler->lvaTable[varNum].lvOnFrame as we don't set it for
6986         // arguments of vararg functions to avoid reporting them to GC.
6987         noway_assert(!compiler->lvaGetDesc(varNum)->lvRegister);
6988         unsigned cookieOffset = compiler->lvaGetDesc(compiler->lvaVarargsHandleArg)->GetStackOffset();
6989         unsigned varOffset    = compiler->lvaGetDesc(varNum)->GetStackOffset();
6990
6991         noway_assert(cookieOffset < varOffset);
6992         unsigned offset     = varOffset - cookieOffset;
6993         unsigned stkArgSize = compiler->compArgSize - intRegState.rsCalleeRegArgCount * REGSIZE_BYTES;
6994         noway_assert(offset < stkArgSize);
6995         offset = stkArgSize - offset;
6996
6997         varLoc->vlType                   = VLT_FIXED_VA;
6998         varLoc->vlFixedVarArg.vlfvOffset = offset;
6999     }
7000
7001 #endif // TARGET_X86
7002
7003     VarName name = nullptr;
7004
7005 #ifdef DEBUG
7006
7007     for (unsigned scopeNum = 0; scopeNum < compiler->info.compVarScopesCount; scopeNum++)
7008     {
7009         if (LVnum == compiler->info.compVarScopes[scopeNum].vsdLVnum)
7010         {
7011             name = compiler->info.compVarScopes[scopeNum].vsdName;
7012         }
7013     }
7014
7015     // Hang on to this compiler->info.
7016
7017     TrnslLocalVarInfo& tlvi = genTrnslLocalVarInfo[which];
7018
7019     tlvi.tlviVarNum    = ilVarNum;
7020     tlvi.tlviLVnum     = LVnum;
7021     tlvi.tlviName      = name;
7022     tlvi.tlviStartPC   = startOffs;
7023     tlvi.tlviLength    = length;
7024     tlvi.tlviAvailable = avail;
7025     tlvi.tlviVarLoc    = *varLoc;
7026
7027 #endif // DEBUG
7028
7029     compiler->eeSetLVinfo(which, startOffs, length, ilVarNum, *varLoc);
7030 }
7031
7032 /*****************************************************************************/
7033 #ifdef LATE_DISASM
7034 #if defined(DEBUG)
7035 /*****************************************************************************
7036  *                          CompilerRegName
7037  *
7038  * Can be called only after lviSetLocalVarInfo() has been called
7039  */
7040
7041 /* virtual */
7042 const char* CodeGen::siRegVarName(size_t offs, size_t size, unsigned reg)
7043 {
7044     if (!compiler->opts.compScopeInfo)
7045         return nullptr;
7046
7047     if (compiler->info.compVarScopesCount == 0)
7048         return nullptr;
7049
7050     noway_assert(genTrnslLocalVarCount == 0 || genTrnslLocalVarInfo);
7051
7052     for (unsigned i = 0; i < genTrnslLocalVarCount; i++)
7053     {
7054         if ((genTrnslLocalVarInfo[i].tlviVarLoc.vlIsInReg((regNumber)reg)) &&
7055             (genTrnslLocalVarInfo[i].tlviAvailable == true) && (genTrnslLocalVarInfo[i].tlviStartPC <= offs + size) &&
7056             (genTrnslLocalVarInfo[i].tlviStartPC + genTrnslLocalVarInfo[i].tlviLength > offs))
7057         {
7058             return genTrnslLocalVarInfo[i].tlviName ? compiler->VarNameToStr(genTrnslLocalVarInfo[i].tlviName) : NULL;
7059         }
7060     }
7061
7062     return NULL;
7063 }
7064
7065 /*****************************************************************************
7066  *                          CompilerStkName
7067  *
7068  * Can be called only after lviSetLocalVarInfo() has been called
7069  */
7070
7071 /* virtual */
7072 const char* CodeGen::siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs)
7073 {
7074     if (!compiler->opts.compScopeInfo)
7075         return nullptr;
7076
7077     if (compiler->info.compVarScopesCount == 0)
7078         return nullptr;
7079
7080     noway_assert(genTrnslLocalVarCount == 0 || genTrnslLocalVarInfo);
7081
7082     for (unsigned i = 0; i < genTrnslLocalVarCount; i++)
7083     {
7084         if ((genTrnslLocalVarInfo[i].tlviVarLoc.vlIsOnStack((regNumber)reg, stkOffs)) &&
7085             (genTrnslLocalVarInfo[i].tlviAvailable == true) && (genTrnslLocalVarInfo[i].tlviStartPC <= offs + size) &&
7086             (genTrnslLocalVarInfo[i].tlviStartPC + genTrnslLocalVarInfo[i].tlviLength > offs))
7087         {
7088             return genTrnslLocalVarInfo[i].tlviName ? compiler->VarNameToStr(genTrnslLocalVarInfo[i].tlviName) : NULL;
7089         }
7090     }
7091
7092     return NULL;
7093 }
7094
7095 /*****************************************************************************/
7096 #endif // defined(DEBUG)
7097 #endif // LATE_DISASM
7098
7099 #ifdef DEBUG
7100
7101 /*****************************************************************************
7102  *  Display a IPmappingDsc. Pass -1 as mappingNum to not display a mapping number.
7103  */
7104
7105 void CodeGen::genIPmappingDisp(unsigned mappingNum, const IPmappingDsc* ipMapping)
7106 {
7107     if (mappingNum != unsigned(-1))
7108     {
7109         printf("%d: ", mappingNum);
7110     }
7111
7112     switch (ipMapping->ipmdKind)
7113     {
7114         case IPmappingDscKind::Prolog:
7115             printf("PROLOG");
7116             break;
7117         case IPmappingDscKind::Epilog:
7118             printf("EPILOG");
7119             break;
7120         case IPmappingDscKind::NoMapping:
7121             printf("NO_MAP");
7122             break;
7123         case IPmappingDscKind::Normal:
7124             const ILLocation& loc = ipMapping->ipmdLoc;
7125             Compiler::eeDispILOffs(loc.GetOffset());
7126             if (loc.IsStackEmpty())
7127             {
7128                 printf(" STACK_EMPTY");
7129             }
7130
7131             if (loc.IsCall())
7132             {
7133                 printf(" CALL_INSTRUCTION");
7134             }
7135
7136             break;
7137     }
7138
7139     printf(" ");
7140     ipMapping->ipmdNativeLoc.Print(compiler->compMethodID);
7141     // We can only call this after code generation. Is there any way to tell when it's legal to call?
7142     // printf(" [%x]", ipMapping->ipmdNativeLoc.CodeOffset(GetEmitter()));
7143
7144     if (ipMapping->ipmdIsLabel)
7145     {
7146         printf(" label");
7147     }
7148
7149     printf("\n");
7150 }
7151
7152 void CodeGen::genIPmappingListDisp()
7153 {
7154     unsigned mappingNum = 0;
7155
7156     for (IPmappingDsc& dsc : compiler->genIPmappings)
7157     {
7158         genIPmappingDisp(mappingNum, &dsc);
7159         ++mappingNum;
7160     }
7161 }
7162
7163 #endif // DEBUG
7164
7165 /*****************************************************************************
7166  *
7167  *  Append an IPmappingDsc struct to the list that we're maintaining
7168  *  for the debugger.
7169  *  Record the instr offset as being at the current code gen position.
7170  */
7171
7172 void CodeGen::genIPmappingAdd(IPmappingDscKind kind, const DebugInfo& di, bool isLabel)
7173 {
7174     if (!compiler->opts.compDbgInfo)
7175     {
7176         return;
7177     }
7178
7179     assert((kind == IPmappingDscKind::Normal) == di.IsValid());
7180
7181     switch (kind)
7182     {
7183         case IPmappingDscKind::Prolog:
7184         case IPmappingDscKind::Epilog:
7185             break;
7186
7187         default:
7188
7189             if (kind == IPmappingDscKind::Normal)
7190             {
7191                 noway_assert(di.GetLocation().GetOffset() <= compiler->info.compILCodeSize);
7192             }
7193
7194             // Ignore this one if it's the same IL location as the last one we saw.
7195             // Note that we'll let through two identical IL offsets if the flag bits
7196             // differ, or two identical "special" mappings (e.g., PROLOG).
7197             if ((compiler->genIPmappings.size() > 0) && (kind == compiler->genIPmappings.back().ipmdKind) &&
7198                 (di.GetLocation() == compiler->genIPmappings.back().ipmdLoc))
7199             {
7200                 JITDUMP("genIPmappingAdd: ignoring duplicate IL offset 0x%x\n", di.GetLocation().GetOffset());
7201                 return;
7202             }
7203             break;
7204     }
7205
7206     IPmappingDsc addMapping;
7207     addMapping.ipmdNativeLoc.CaptureLocation(GetEmitter());
7208     addMapping.ipmdKind    = kind;
7209     addMapping.ipmdLoc     = di.GetLocation();
7210     addMapping.ipmdIsLabel = isLabel;
7211
7212     assert((kind == IPmappingDscKind::Normal) == addMapping.ipmdLoc.IsValid());
7213     compiler->genIPmappings.push_back(addMapping);
7214
7215 #ifdef DEBUG
7216     if (verbose)
7217     {
7218         printf("Added IP mapping: ");
7219         genIPmappingDisp(unsigned(-1), &addMapping);
7220     }
7221 #endif // DEBUG
7222 }
7223
7224 /*****************************************************************************
7225  *
7226  *  Prepend an IPmappingDsc struct to the list that we're maintaining
7227  *  for the debugger.
7228  */
7229 void CodeGen::genIPmappingAddToFront(IPmappingDscKind kind, const DebugInfo& di, bool isLabel)
7230 {
7231     if (!compiler->opts.compDbgInfo)
7232     {
7233         return;
7234     }
7235
7236     noway_assert((kind != IPmappingDscKind::Normal) ||
7237                  (di.IsValid() && (di.GetLocation().GetOffset() <= compiler->info.compILCodeSize)));
7238
7239     /* Create a mapping entry and prepend it to the list */
7240
7241     IPmappingDsc addMapping;
7242     addMapping.ipmdNativeLoc.CaptureLocation(GetEmitter());
7243     addMapping.ipmdKind    = kind;
7244     addMapping.ipmdLoc     = di.GetLocation();
7245     addMapping.ipmdIsLabel = isLabel;
7246     compiler->genIPmappings.push_front(addMapping);
7247
7248 #ifdef DEBUG
7249     if (verbose)
7250     {
7251         printf("Added IP mapping to front: ");
7252         genIPmappingDisp(unsigned(-1), &addMapping);
7253     }
7254 #endif // DEBUG
7255 }
7256
7257 /*****************************************************************************/
7258
7259 void CodeGen::genEnsureCodeEmitted(const DebugInfo& di)
7260 {
7261     if (!compiler->opts.compDbgCode)
7262     {
7263         return;
7264     }
7265
7266     if (!di.IsValid())
7267     {
7268         return;
7269     }
7270
7271     // If other IL were offsets reported, skip
7272
7273     if (compiler->genIPmappings.size() <= 0)
7274     {
7275         return;
7276     }
7277
7278     const IPmappingDsc& prev = compiler->genIPmappings.back();
7279     if (prev.ipmdLoc != di.GetLocation())
7280     {
7281         return;
7282     }
7283
7284     // di represents the last reported offset. Make sure that we generated native code
7285
7286     if (prev.ipmdNativeLoc.IsCurrentLocation(GetEmitter()))
7287     {
7288         instGen(INS_nop);
7289     }
7290 }
7291
7292 //------------------------------------------------------------------------
7293 // genIPmappingGen: Shut down the IP-mapping logic, report the info to the EE.
7294 //
7295 void CodeGen::genIPmappingGen()
7296 {
7297     if (!compiler->opts.compDbgInfo)
7298     {
7299         return;
7300     }
7301
7302     JITDUMP("*************** In genIPmappingGen()\n");
7303
7304     if (compiler->genIPmappings.size() <= 0)
7305     {
7306         compiler->eeSetLIcount(0);
7307         compiler->eeSetLIdone();
7308         return;
7309     }
7310
7311     UNATIVE_OFFSET prevNativeOfs = UNATIVE_OFFSET(~0);
7312     for (jitstd::list<IPmappingDsc>::iterator it = compiler->genIPmappings.begin();
7313          it != compiler->genIPmappings.end();)
7314     {
7315         UNATIVE_OFFSET dscNativeOfs = it->ipmdNativeLoc.CodeOffset(GetEmitter());
7316         if (dscNativeOfs != prevNativeOfs)
7317         {
7318             prevNativeOfs = dscNativeOfs;
7319             ++it;
7320             continue;
7321         }
7322
7323         // If we have a previous offset we should have a previous mapping.
7324         assert(it != compiler->genIPmappings.begin());
7325         jitstd::list<IPmappingDsc>::iterator prev = it;
7326         --prev;
7327
7328         // Prev and current mappings have same native offset.
7329         // If one does not map to IL then remove that one.
7330         if (prev->ipmdKind == IPmappingDscKind::NoMapping)
7331         {
7332             compiler->genIPmappings.erase(prev);
7333             ++it;
7334             continue;
7335         }
7336
7337         if (it->ipmdKind == IPmappingDscKind::NoMapping)
7338         {
7339             it = compiler->genIPmappings.erase(it);
7340             continue;
7341         }
7342
7343         // Both have mappings.
7344         // If previous is the prolog, keep both if this one is at IL offset 0.
7345         // (TODO: Why? Debugger has no problem breaking on the prolog mapping
7346         // it seems.)
7347         if ((prev->ipmdKind == IPmappingDscKind::Prolog) && (it->ipmdKind == IPmappingDscKind::Normal) &&
7348             (it->ipmdLoc.GetOffset() == 0))
7349         {
7350             ++it;
7351             continue;
7352         }
7353
7354         // For the special case of an IL instruction with no body followed by
7355         // the epilog (say ret void immediately preceding the method end), we
7356         // leave both entries in, so that we'll stop at the (empty) ret
7357         // statement if the user tries to put a breakpoint there, and then have
7358         // the option of seeing the epilog or not based on SetUnmappedStopMask
7359         // for the stepper.
7360         if (it->ipmdKind == IPmappingDscKind::Epilog)
7361         {
7362             ++it;
7363             continue;
7364         }
7365
7366         // For managed return values we store all calls. Keep both in this case
7367         // too.
7368         if (((prev->ipmdKind == IPmappingDscKind::Normal) && (prev->ipmdLoc.IsCall())) ||
7369             ((it->ipmdKind == IPmappingDscKind::Normal) && (it->ipmdLoc.IsCall())))
7370         {
7371             ++it;
7372             continue;
7373         }
7374
7375         // Otherwise report the higher offset unless the previous mapping is a
7376         // label.
7377         if (prev->ipmdIsLabel)
7378         {
7379             it = compiler->genIPmappings.erase(it);
7380         }
7381         else
7382         {
7383             compiler->genIPmappings.erase(prev);
7384             ++it;
7385         }
7386     }
7387
7388     // Tell them how many mapping records we've got
7389
7390     compiler->eeSetLIcount(static_cast<unsigned int>(compiler->genIPmappings.size()));
7391
7392     // Now tell them about the mappings
7393     unsigned int mappingIdx = 0;
7394     for (const IPmappingDsc& dsc : compiler->genIPmappings)
7395     {
7396         compiler->eeSetLIinfo(mappingIdx++, dsc.ipmdNativeLoc.CodeOffset(GetEmitter()), dsc.ipmdKind, dsc.ipmdLoc);
7397     }
7398
7399 #if 0
7400     // TODO-Review:
7401     //This check is disabled.  It is always true that any time this check asserts, the debugger would have a
7402     //problem with IL source level debugging.  However, for a C# file, it only matters if things are on
7403     //different source lines.  As a result, we have all sorts of latent problems with how we emit debug
7404     //info, but very few actual ones.  Whenever someone wants to tackle that problem in general, turn this
7405     //assert back on.
7406     if (compiler->opts.compDbgCode)
7407     {
7408         //Assert that the first instruction of every basic block with more than one incoming edge has a
7409         //different sequence point from each incoming block.
7410         //
7411         //It turns out that the only thing we really have to assert is that the first statement in each basic
7412         //block has an IL offset and appears in eeBoundaries.
7413         for (BasicBlock* const block : compiler->Blocks())
7414         {
7415             Statement* stmt = block->firstStmt();
7416             if ((block->bbRefs > 1) && (stmt != nullptr))
7417             {
7418                 bool found = false;
7419                 DebugInfo rootInfo = stmt->GetDebugInfo().GetRoot();
7420                 if (rootInfo.IsValid())
7421                 {
7422                     for (unsigned i = 0; i < compiler->eeBoundariesCount; ++i)
7423                     {
7424                         if (compiler->eeBoundaries[i].ilOffset == rootInfo.GetLocation().GetOffset())
7425                         {
7426                             found = true;
7427                             break;
7428                         }
7429                     }
7430                 }
7431                 noway_assert(found && "A basic block that is a jump target did not start a new sequence point.");
7432             }
7433         }
7434     }
7435 #endif // 0
7436
7437     compiler->eeSetLIdone();
7438 }
7439
7440 #ifdef DEBUG
7441 //------------------------------------------------------------------------
7442 // genReportRichDebugInfoInlineTreeToFile:
7443 //   Recursively process a context in the inline tree and write information about it to a file.
7444 //
7445 // Parameters:
7446 //   file - the file
7447 //   context - the context
7448 //   first - whether this is the first of the siblings being written out
7449 //
7450 void CodeGen::genReportRichDebugInfoInlineTreeToFile(FILE* file, InlineContext* context, bool* first)
7451 {
7452     if (context->GetSibling() != nullptr)
7453     {
7454         genReportRichDebugInfoInlineTreeToFile(file, context->GetSibling(), first);
7455     }
7456
7457     if (context->IsSuccess())
7458     {
7459         if (!*first)
7460         {
7461             fprintf(file, ",");
7462         }
7463
7464         *first = false;
7465
7466         fprintf(file, "{\"Ordinal\":%u,", context->GetOrdinal());
7467         fprintf(file, "\"MethodID\":%lld,", (int64_t)context->GetCallee());
7468         fprintf(file, "\"ILOffset\":%u,", context->GetLocation().GetOffset());
7469         fprintf(file, "\"LocationFlags\":%u,", (uint32_t)context->GetLocation().EncodeSourceTypes());
7470         fprintf(file, "\"ExactILOffset\":%u,", context->GetActualCallOffset());
7471         auto append = [&]() {
7472             char        buffer[256];
7473             const char* methodName = compiler->eeGetMethodName(context->GetCallee(), buffer, sizeof(buffer));
7474             fprintf(file, "\"MethodName\":\"%s\",", methodName);
7475         };
7476         append();
7477         fprintf(file, "\"Inlinees\":[");
7478         if (context->GetChild() != nullptr)
7479         {
7480             bool childFirst = true;
7481             genReportRichDebugInfoInlineTreeToFile(file, context->GetChild(), &childFirst);
7482         }
7483         fprintf(file, "]}");
7484     }
7485 }
7486
7487 //------------------------------------------------------------------------
7488 // genReportRichDebugInfoToFile:
7489 //   Write rich debug info in JSON format to file specified by environment variable.
7490 //
7491 void CodeGen::genReportRichDebugInfoToFile()
7492 {
7493     if (JitConfig.WriteRichDebugInfoFile() == nullptr)
7494     {
7495         return;
7496     }
7497
7498     static CritSecObject s_critSect;
7499     CritSecHolder        holder(s_critSect);
7500
7501     FILE* file = _wfopen(JitConfig.WriteRichDebugInfoFile(), W("a"));
7502     if (file == nullptr)
7503     {
7504         return;
7505     }
7506
7507     // MethodID in ETW events are the method handles.
7508     fprintf(file, "{\"MethodID\":%lld,", (INT64)compiler->info.compMethodHnd);
7509     // Print inline tree.
7510     fprintf(file, "\"InlineTree\":");
7511
7512     bool first = true;
7513     genReportRichDebugInfoInlineTreeToFile(file, compiler->compInlineContext, &first);
7514     fprintf(file, ",\"Mappings\":[");
7515     first = true;
7516     for (RichIPMapping& mapping : compiler->genRichIPmappings)
7517     {
7518         if (!first)
7519         {
7520             fprintf(file, ",");
7521         }
7522
7523         first = false;
7524
7525         fprintf(file, "{\"NativeOffset\":%u,\"InlineContext\":%u,\"ILOffset\":%u}",
7526                 mapping.nativeLoc.CodeOffset(GetEmitter()), mapping.debugInfo.GetInlineContext()->GetOrdinal(),
7527                 mapping.debugInfo.GetLocation().GetOffset());
7528     }
7529
7530     fprintf(file, "]}\n");
7531
7532     fclose(file);
7533 }
7534
7535 #endif
7536
7537 //------------------------------------------------------------------------
7538 // genRecordRichDebugInfoInlineTree:
7539 //   Recursively process a context in the inline tree and record information
7540 //   about it.
7541 //
7542 // Parameters:
7543 //   context - the inline context
7544 //   nodes   - the array to record into
7545 //
7546 void CodeGen::genRecordRichDebugInfoInlineTree(InlineContext* context, ICorDebugInfo::InlineTreeNode* nodes)
7547 {
7548     if (context->IsSuccess())
7549     {
7550         // We expect 1 + NumInlines unique ordinals
7551         assert(context->GetOrdinal() <= compiler->m_inlineStrategy->GetInlineCount());
7552
7553         ICorDebugInfo::InlineTreeNode* node = &nodes[context->GetOrdinal()];
7554         node->Method                        = context->GetCallee();
7555         node->ILOffset                      = context->GetActualCallOffset();
7556         node->Child                         = context->GetChild() == nullptr ? 0 : context->GetChild()->GetOrdinal();
7557         node->Sibling = context->GetSibling() == nullptr ? 0 : context->GetSibling()->GetOrdinal();
7558     }
7559
7560     if (context->GetSibling() != nullptr)
7561     {
7562         genRecordRichDebugInfoInlineTree(context->GetSibling(), nodes);
7563     }
7564
7565     if (context->GetChild() != nullptr)
7566     {
7567         genRecordRichDebugInfoInlineTree(context->GetChild(), nodes);
7568     }
7569 }
7570
7571 //------------------------------------------------------------------------
7572 // genReportRichDebugInfo:
7573 //   If enabled, report rich debugging information to file and/or EE.
7574 //
7575 void CodeGen::genReportRichDebugInfo()
7576 {
7577     INDEBUG(genReportRichDebugInfoToFile());
7578
7579     if (JitConfig.RichDebugInfo() == 0)
7580     {
7581         return;
7582     }
7583
7584     unsigned numContexts     = 1 + compiler->m_inlineStrategy->GetInlineCount();
7585     unsigned numRichMappings = static_cast<unsigned>(compiler->genRichIPmappings.size());
7586
7587     ICorDebugInfo::InlineTreeNode* inlineTree = static_cast<ICorDebugInfo::InlineTreeNode*>(
7588         compiler->info.compCompHnd->allocateArray(numContexts * sizeof(ICorDebugInfo::InlineTreeNode)));
7589     ICorDebugInfo::RichOffsetMapping* mappings = static_cast<ICorDebugInfo::RichOffsetMapping*>(
7590         compiler->info.compCompHnd->allocateArray(numRichMappings * sizeof(ICorDebugInfo::RichOffsetMapping)));
7591
7592     memset(inlineTree, 0, numContexts * sizeof(ICorDebugInfo::InlineTreeNode));
7593     memset(mappings, 0, numRichMappings * sizeof(ICorDebugInfo::RichOffsetMapping));
7594
7595     genRecordRichDebugInfoInlineTree(compiler->compInlineContext, inlineTree);
7596
7597 #ifdef DEBUG
7598     for (unsigned i = 0; i < numContexts; i++)
7599     {
7600         assert(inlineTree[i].Method != NO_METHOD_HANDLE);
7601     }
7602 #endif
7603
7604     size_t mappingIndex = 0;
7605     for (const RichIPMapping& richMapping : compiler->genRichIPmappings)
7606     {
7607         ICorDebugInfo::RichOffsetMapping* mapping = &mappings[mappingIndex];
7608         assert(richMapping.debugInfo.IsValid());
7609         mapping->NativeOffset = richMapping.nativeLoc.CodeOffset(GetEmitter());
7610         mapping->Inlinee      = richMapping.debugInfo.GetInlineContext()->GetOrdinal();
7611         mapping->ILOffset     = richMapping.debugInfo.GetLocation().GetOffset();
7612         mapping->Source       = richMapping.debugInfo.GetLocation().EncodeSourceTypes();
7613
7614         mappingIndex++;
7615     }
7616
7617     compiler->info.compCompHnd->reportRichMappings(inlineTree, numContexts, mappings, numRichMappings);
7618 }
7619
7620 //------------------------------------------------------------------------
7621 // genAddRichIPMappingHere:
7622 //   Create a rich IP mapping at the current emit location using the specified
7623 //   debug information.
7624 //
7625 // Parameters:
7626 //   di - the debug information
7627 //
7628 void CodeGen::genAddRichIPMappingHere(const DebugInfo& di)
7629 {
7630     RichIPMapping mapping;
7631     mapping.nativeLoc.CaptureLocation(GetEmitter());
7632     mapping.debugInfo = di;
7633     compiler->genRichIPmappings.push_back(mapping);
7634 }
7635
7636 /*============================================================================
7637  *
7638  *   These are empty stubs to help the late dis-assembler to compile
7639  *   if the late disassembler is being built into a non-DEBUG build.
7640  *
7641  *============================================================================
7642  */
7643
7644 #if defined(LATE_DISASM)
7645 #if !defined(DEBUG)
7646
7647 /* virtual */
7648 const char* CodeGen::siRegVarName(size_t offs, size_t size, unsigned reg)
7649 {
7650     return NULL;
7651 }
7652
7653 /* virtual */
7654 const char* CodeGen::siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs)
7655 {
7656     return NULL;
7657 }
7658
7659 /*****************************************************************************/
7660 #endif // !defined(DEBUG)
7661 #endif // defined(LATE_DISASM)
7662
7663 //------------------------------------------------------------------------
7664 // indirForm: Make a temporary indir we can feed to pattern matching routines
7665 //    in cases where we don't want to instantiate all the indirs that happen.
7666 //
7667 /* static */ GenTreeIndir CodeGen::indirForm(var_types type, GenTree* base)
7668 {
7669     GenTreeIndir i(GT_IND, type, base, nullptr);
7670     i.SetRegNum(REG_NA);
7671     i.SetContained();
7672     return i;
7673 }
7674
7675 //------------------------------------------------------------------------
7676 // indirForm: Make a temporary indir we can feed to pattern matching routines
7677 //    in cases where we don't want to instantiate all the indirs that happen.
7678 //
7679 /* static */ GenTreeStoreInd CodeGen::storeIndirForm(var_types type, GenTree* base, GenTree* data)
7680 {
7681     GenTreeStoreInd i(type, base, data);
7682     i.SetRegNum(REG_NA);
7683     return i;
7684 }
7685
7686 //------------------------------------------------------------------------
7687 // intForm: Make a temporary int we can feed to pattern matching routines
7688 //    in cases where we don't want to instantiate.
7689 //
7690 GenTreeIntCon CodeGen::intForm(var_types type, ssize_t value)
7691 {
7692     GenTreeIntCon i(type, value);
7693     i.SetRegNum(REG_NA);
7694     return i;
7695 }
7696
7697 #if defined(TARGET_X86) || defined(TARGET_ARM)
7698 //------------------------------------------------------------------------
7699 // genLongReturn: Generates code for long return statement for x86 and arm.
7700 //
7701 // Note: treeNode's and op1's registers are already consumed.
7702 //
7703 // Arguments:
7704 //    treeNode - The GT_RETURN or GT_RETFILT tree node with LONG return type.
7705 //
7706 // Return Value:
7707 //    None
7708 //
7709 void CodeGen::genLongReturn(GenTree* treeNode)
7710 {
7711     assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
7712     assert(treeNode->TypeGet() == TYP_LONG);
7713     GenTree*  op1        = treeNode->gtGetOp1();
7714     var_types targetType = treeNode->TypeGet();
7715
7716     assert(op1 != nullptr);
7717     assert(op1->OperGet() == GT_LONG);
7718     GenTree* loRetVal = op1->gtGetOp1();
7719     GenTree* hiRetVal = op1->gtGetOp2();
7720     assert((loRetVal->GetRegNum() != REG_NA) && (hiRetVal->GetRegNum() != REG_NA));
7721
7722     genConsumeReg(loRetVal);
7723     genConsumeReg(hiRetVal);
7724
7725     inst_Mov(targetType, REG_LNGRET_LO, loRetVal->GetRegNum(), /* canSkip */ true, emitActualTypeSize(TYP_INT));
7726     inst_Mov(targetType, REG_LNGRET_HI, hiRetVal->GetRegNum(), /* canSkip */ true, emitActualTypeSize(TYP_INT));
7727 }
7728 #endif // TARGET_X86 || TARGET_ARM
7729
7730 //------------------------------------------------------------------------
7731 // genReturn: Generates code for return statement.
7732 //            In case of struct return, delegates to the genStructReturn method.
7733 //
7734 // Arguments:
7735 //    treeNode - The GT_RETURN or GT_RETFILT tree node.
7736 //
7737 // Return Value:
7738 //    None
7739 //
7740 void CodeGen::genReturn(GenTree* treeNode)
7741 {
7742     assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
7743     GenTree*  op1        = treeNode->gtGetOp1();
7744     var_types targetType = treeNode->TypeGet();
7745
7746     // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
7747     // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
7748     // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
7749     assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
7750
7751 #ifdef DEBUG
7752     if (targetType == TYP_VOID)
7753     {
7754         assert(op1 == nullptr);
7755     }
7756 #endif // DEBUG
7757
7758 #if defined(TARGET_X86) || defined(TARGET_ARM)
7759     if (targetType == TYP_LONG)
7760     {
7761         genLongReturn(treeNode);
7762     }
7763     else
7764 #endif // TARGET_X86 || TARGET_ARM
7765     {
7766         if (isStructReturn(treeNode))
7767         {
7768             genStructReturn(treeNode);
7769         }
7770         else if (targetType != TYP_VOID)
7771         {
7772             assert(op1 != nullptr);
7773             noway_assert(op1->GetRegNum() != REG_NA);
7774
7775             // !! NOTE !! genConsumeReg will clear op1 as GC ref after it has
7776             // consumed a reg for the operand. This is because the variable
7777             // is dead after return. But we are issuing more instructions
7778             // like "profiler leave callback" after this consumption. So
7779             // if you are issuing more instructions after this point,
7780             // remember to keep the variable live up until the new method
7781             // exit point where it is actually dead.
7782             genConsumeReg(op1);
7783
7784 #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
7785             genSimpleReturn(treeNode);
7786 #else // !TARGET_ARM64 || !TARGET_LOONGARCH64 || !TARGET_RISCV64
7787 #if defined(TARGET_X86)
7788             if (varTypeUsesFloatReg(treeNode))
7789             {
7790                 genFloatReturn(treeNode);
7791             }
7792             else
7793 #elif defined(TARGET_ARM)
7794             if (varTypeUsesFloatReg(treeNode) && (compiler->opts.compUseSoftFP || compiler->info.compIsVarArgs))
7795             {
7796                 if (targetType == TYP_FLOAT)
7797                 {
7798                     GetEmitter()->emitIns_Mov(INS_vmov_f2i, EA_4BYTE, REG_INTRET, op1->GetRegNum(),
7799                                               /* canSkip */ false);
7800                 }
7801                 else
7802                 {
7803                     assert(targetType == TYP_DOUBLE);
7804                     GetEmitter()->emitIns_R_R_R(INS_vmov_d2i, EA_8BYTE, REG_INTRET, REG_NEXT(REG_INTRET),
7805                                                 op1->GetRegNum());
7806                 }
7807             }
7808             else
7809 #endif // TARGET_ARM
7810             {
7811                 regNumber retReg;
7812
7813                 if (varTypeUsesIntReg(treeNode))
7814                 {
7815                     retReg = REG_INTRET;
7816                 }
7817                 else
7818                 {
7819                     assert(varTypeUsesFloatReg(treeNode));
7820                     retReg = REG_FLOATRET;
7821                 }
7822
7823                 inst_Mov_Extend(targetType, /* srcInReg */ true, retReg, op1->GetRegNum(), /* canSkip */ true);
7824             }
7825 #endif // !TARGET_ARM64 || !TARGET_LOONGARCH64 || !TARGET_RISCV64
7826         }
7827     }
7828
7829 #ifdef PROFILING_SUPPORTED
7830     // !! Note !!
7831     // TODO-AMD64-Unix: If the profiler hook is implemented on *nix, make sure for 2 register returned structs
7832     //                  the RAX and RDX needs to be kept alive. Make the necessary changes in lowerxarch.cpp
7833     //                  in the handling of the GT_RETURN statement.
7834     //                  Such structs containing GC pointers need to be handled by calling gcInfo.gcMarkRegSetNpt
7835     //                  for the return registers containing GC refs.
7836     //
7837     // Reason for not materializing Leave callback as a GT_PROF_HOOK node after GT_RETURN:
7838     // In flowgraph and other places assert that the last node of a block marked as
7839     // BBJ_RETURN is either a GT_RETURN or GT_JMP or a tail call.  It would be nice to
7840     // maintain such an invariant irrespective of whether profiler hook needed or not.
7841     // Also, there is not much to be gained by materializing it as an explicit node.
7842     //
7843     // There should be a single return block while generating profiler ELT callbacks,
7844     // so we just look for that block to trigger insertion of the profile hook.
7845     if ((compiler->compCurBB == compiler->genReturnBB) && compiler->compIsProfilerHookNeeded())
7846     {
7847         // !! NOTE !!
7848         // Since we are invalidating the assumption that we would slip into the epilog
7849         // right after the "return", we need to preserve the return reg's GC state
7850         // across the call until actual method return.
7851
7852         ReturnTypeDesc retTypeDesc = compiler->compRetTypeDesc;
7853         unsigned       retRegCount = retTypeDesc.GetReturnRegCount();
7854
7855         if (compiler->compMethodReturnsRetBufAddr())
7856         {
7857             gcInfo.gcMarkRegPtrVal(REG_INTRET, TYP_BYREF);
7858         }
7859         else
7860         {
7861             for (unsigned i = 0; i < retRegCount; ++i)
7862             {
7863                 if (varTypeIsGC(retTypeDesc.GetReturnRegType(i)))
7864                 {
7865                     gcInfo.gcMarkRegPtrVal(retTypeDesc.GetABIReturnReg(i), retTypeDesc.GetReturnRegType(i));
7866                 }
7867             }
7868         }
7869
7870         genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_LEAVE);
7871
7872         if (compiler->compMethodReturnsRetBufAddr())
7873         {
7874             gcInfo.gcMarkRegSetNpt(genRegMask(REG_INTRET));
7875         }
7876         else
7877         {
7878             for (unsigned i = 0; i < retRegCount; ++i)
7879             {
7880                 if (varTypeIsGC(retTypeDesc.GetReturnRegType(i)))
7881                 {
7882                     gcInfo.gcMarkRegSetNpt(genRegMask(retTypeDesc.GetABIReturnReg(i)));
7883                 }
7884             }
7885         }
7886     }
7887 #endif // PROFILING_SUPPORTED
7888
7889 #if defined(DEBUG) && defined(TARGET_XARCH)
7890     bool doStackPointerCheck = compiler->opts.compStackCheckOnRet;
7891
7892 #if defined(FEATURE_EH_FUNCLETS)
7893     // Don't do stack pointer check at the return from a funclet; only for the main function.
7894     if (compiler->funCurrentFunc()->funKind != FUNC_ROOT)
7895     {
7896         doStackPointerCheck = false;
7897     }
7898 #else  // !FEATURE_EH_FUNCLETS
7899     // Don't generate stack checks for x86 finally/filter EH returns: these are not invoked
7900     // with the same SP as the main function. See also CodeGen::genEHFinallyOrFilterRet().
7901     if (compiler->compCurBB->KindIs(BBJ_EHFINALLYRET, BBJ_EHFAULTRET, BBJ_EHFILTERRET))
7902     {
7903         doStackPointerCheck = false;
7904     }
7905 #endif // !FEATURE_EH_FUNCLETS
7906
7907     genStackPointerCheck(doStackPointerCheck, compiler->lvaReturnSpCheck);
7908 #endif // defined(DEBUG) && defined(TARGET_XARCH)
7909 }
7910
7911 //------------------------------------------------------------------------
7912 // isStructReturn: Returns whether the 'treeNode' is returning a struct.
7913 //
7914 // Arguments:
7915 //    treeNode - The tree node to evaluate whether is a struct return.
7916 //
7917 // Return Value:
7918 //    Returns true if the 'treeNode" is a GT_RETURN node of type struct.
7919 //    Otherwise returns false.
7920 //
7921 bool CodeGen::isStructReturn(GenTree* treeNode)
7922 {
7923     // This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN.
7924     // For the GT_RET_FILT, the return is always a bool or a void, for the end of a finally block.
7925     noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT);
7926     if (treeNode->OperGet() != GT_RETURN)
7927     {
7928         return false;
7929     }
7930
7931 #if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)
7932     assert(!varTypeIsStruct(treeNode));
7933     return false;
7934 #else
7935     return varTypeIsStruct(treeNode) && (compiler->info.compRetNativeType == TYP_STRUCT);
7936 #endif
7937 }
7938
7939 //------------------------------------------------------------------------
7940 // genStructReturn: Generates code for returning a struct.
7941 //
7942 // Arguments:
7943 //    treeNode - The GT_RETURN tree node.
7944 //
7945 // Return Value:
7946 //    None
7947 //
7948 // Assumption:
7949 //    op1 of GT_RETURN node is either GT_LCL_VAR or multi-reg GT_CALL
7950 //
7951 void CodeGen::genStructReturn(GenTree* treeNode)
7952 {
7953     assert(treeNode->OperGet() == GT_RETURN);
7954
7955     genConsumeRegs(treeNode->gtGetOp1());
7956
7957     GenTree* op1       = treeNode->gtGetOp1();
7958     GenTree* actualOp1 = op1->gtSkipReloadOrCopy();
7959
7960     ReturnTypeDesc retTypeDesc = compiler->compRetTypeDesc;
7961     const unsigned regCount    = retTypeDesc.GetReturnRegCount();
7962     assert(regCount <= MAX_RET_REG_COUNT);
7963
7964 #if FEATURE_MULTIREG_RET
7965     // Right now the only enregisterable structs supported are SIMD vector types.
7966     if (genIsRegCandidateLocal(actualOp1))
7967     {
7968 #if defined(DEBUG)
7969         const GenTreeLclVar* lclVar = actualOp1->AsLclVar();
7970         const LclVarDsc*     varDsc = compiler->lvaGetDesc(lclVar);
7971         assert(varTypeIsSIMD(varDsc->GetRegisterType()));
7972         assert(!lclVar->IsMultiReg());
7973 #endif // DEBUG
7974
7975 #ifdef FEATURE_SIMD
7976         genSIMDSplitReturn(op1, &retTypeDesc);
7977 #endif // FEATURE_SIMD
7978     }
7979     else if (actualOp1->OperIs(GT_LCL_VAR) && !actualOp1->AsLclVar()->IsMultiReg())
7980     {
7981         GenTreeLclVar* lclNode = actualOp1->AsLclVar();
7982         LclVarDsc*     varDsc  = compiler->lvaGetDesc(lclNode);
7983         assert(varDsc->lvIsMultiRegRet);
7984
7985 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
7986         // On LoongArch64, for a struct like "{ int, double }", "retTypeDesc" will be "{ TYP_INT, TYP_DOUBLE }",
7987         // i. e. not include the padding for the first field, and so the general loop below won't work.
7988         var_types type  = retTypeDesc.GetReturnRegType(0);
7989         regNumber toReg = retTypeDesc.GetABIReturnReg(0);
7990         GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), 0);
7991         if (regCount > 1)
7992         {
7993             assert(regCount == 2);
7994             int offset = genTypeSize(type);
7995             type       = retTypeDesc.GetReturnRegType(1);
7996             offset     = (int)((unsigned int)offset < genTypeSize(type) ? genTypeSize(type) : offset);
7997             toReg      = retTypeDesc.GetABIReturnReg(1);
7998             GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset);
7999         }
8000 #else  // !TARGET_LOONGARCH64 && !TARGET_RISCV64
8001         int offset = 0;
8002         for (unsigned i = 0; i < regCount; ++i)
8003         {
8004             var_types type  = retTypeDesc.GetReturnRegType(i);
8005             regNumber toReg = retTypeDesc.GetABIReturnReg(i);
8006             GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset);
8007             offset += genTypeSize(type);
8008         }
8009 #endif // !TARGET_LOONGARCH64 && !TARGET_RISCV64
8010     }
8011     else
8012     {
8013         for (unsigned i = 0; i < regCount; ++i)
8014         {
8015             var_types type    = retTypeDesc.GetReturnRegType(i);
8016             regNumber toReg   = retTypeDesc.GetABIReturnReg(i);
8017             regNumber fromReg = op1->GetRegByIndex(i);
8018             if ((fromReg == REG_NA) && op1->OperIs(GT_COPY))
8019             {
8020                 // A copy that doesn't copy this field will have REG_NA.
8021                 // TODO-Cleanup: It would probably be better to always have a valid reg
8022                 // on a GT_COPY, unless the operand is actually spilled. Then we wouldn't have
8023                 // to check for this case (though we'd have to check in the genRegCopy that the
8024                 // reg is valid).
8025                 fromReg = actualOp1->GetRegByIndex(i);
8026             }
8027             if (fromReg == REG_NA)
8028             {
8029                 // This is a spilled field of a multi-reg lclVar.
8030                 // We currently only mark a lclVar operand as RegOptional, since we don't have a way
8031                 // to mark a multi-reg tree node as used from spill (GTF_NOREG_AT_USE) on a per-reg basis.
8032                 LclVarDsc* varDsc = compiler->lvaGetDesc(actualOp1->AsLclVar());
8033                 assert(varDsc->lvPromoted);
8034                 unsigned fieldVarNum = varDsc->lvFieldLclStart + i;
8035                 assert(compiler->lvaGetDesc(fieldVarNum)->lvOnFrame);
8036
8037                 GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, fieldVarNum, 0);
8038             }
8039             else
8040             {
8041                 // Note that ins_Copy(fromReg, type) will return the appropriate register to copy
8042                 // between register files if needed.
8043                 inst_Mov(type, toReg, fromReg, /* canSkip */ true);
8044             }
8045         }
8046     }
8047 #else // !FEATURE_MULTIREG_RET
8048     unreached();
8049 #endif
8050 }
8051
8052 //----------------------------------------------------------------------------------
8053 // genMultiRegStoreToLocal: store multi-reg value to a local
8054 //
8055 // Arguments:
8056 //    lclNode  -  GenTree of GT_STORE_LCL_VAR
8057 //
8058 // Return Value:
8059 //    None
8060 //
8061 // Assumption:
8062 //    The child of store is a multi-reg node.
8063 //
8064 void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode)
8065 {
8066     assert(lclNode->OperIs(GT_STORE_LCL_VAR));
8067     assert(varTypeIsStruct(lclNode) || varTypeIsMultiReg(lclNode));
8068
8069     GenTree* op1 = lclNode->gtGetOp1();
8070     assert(op1->IsMultiRegNode());
8071     GenTree* actualOp1 = op1->gtSkipReloadOrCopy();
8072     unsigned regCount  = actualOp1->GetMultiRegCount(compiler);
8073     assert(regCount > 1);
8074
8075     // Assumption: current implementation requires that a multi-reg
8076     // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from
8077     // being promoted, unless compiler->lvaEnregMultiRegVars is true.
8078
8079     unsigned   lclNum = lclNode->GetLclNum();
8080     LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum);
8081     if (op1->OperIs(GT_CALL))
8082     {
8083         assert(regCount <= MAX_RET_REG_COUNT);
8084         noway_assert(varDsc->lvIsMultiRegRet);
8085     }
8086
8087 #ifdef FEATURE_SIMD
8088     // Check for the case of an enregistered SIMD type that's returned in multiple registers.
8089     if (varDsc->lvIsRegCandidate() && (lclNode->GetRegNum() != REG_NA))
8090     {
8091         assert(varTypeIsSIMD(lclNode));
8092         genMultiRegStoreToSIMDLocal(lclNode);
8093         return;
8094     }
8095 #endif // FEATURE_SIMD
8096
8097     // We have either a multi-reg local or a local with multiple fields in memory.
8098     //
8099     // The liveness model is as follows:
8100     //    use reg #0 from src, including any reload or copy
8101     //    define reg #0
8102     //    use reg #1 from src, including any reload or copy
8103     //    define reg #1
8104     //    etc.
8105     // Imagine the following scenario:
8106     //    There are 3 registers used. Prior to this node, they occupy registers r3, r2 and r1.
8107     //    There are 3 registers defined by this node. They need to be placed in r1, r2 and r3,
8108     //    in that order.
8109     //
8110     // If we defined the as using all the source registers at once, we'd have to adopt one
8111     // of the following models:
8112     //  - All (or all but one) of the incoming sources are marked "delayFree" so that they won't
8113     //    get the same register as any of the registers being defined. This would result in copies for
8114     //    the common case where the source and destination registers are the same (e.g. when a CALL
8115     //    result is assigned to a lclVar, which is then returned).
8116     //    - For our example (and for many/most cases) we would have to copy or spill all sources.
8117     //  - We allow circular dependencies between source and destination registers. This would require
8118     //    the code generator to determine the order in which the copies must be generated, and would
8119     //    require a temp register in case a swap is required. This complexity would have to be handled
8120     //    in both the normal code generation case, as well as for copies & reloads, as they are currently
8121     //    modeled by the register allocator to happen just prior to the use.
8122     //    - For our example, a temp would be required to swap r1 and r3, unless a swap instruction is
8123     //      available on the target.
8124     //
8125     // By having a multi-reg local use and define each field in order, we avoid these issues, and the
8126     // register allocator will ensure that any conflicts are resolved via spill or inserted COPYs.
8127     // For our example, the register allocator would simple spill r1 because the first def requires it.
8128     // The code generator would move r3  to r1, leave r2 alone, and then load the spilled value into r3.
8129
8130     unsigned offset        = 0;
8131     bool     isMultiRegVar = lclNode->IsMultiRegLclVar();
8132     bool     hasRegs       = false;
8133
8134     if (isMultiRegVar)
8135     {
8136         assert(compiler->lvaEnregMultiRegVars);
8137         assert(regCount == varDsc->lvFieldCnt);
8138     }
8139
8140     for (unsigned i = 0; i < regCount; ++i)
8141     {
8142         regNumber reg     = genConsumeReg(op1, i);
8143         var_types srcType = actualOp1->GetRegTypeByIndex(i);
8144         // genConsumeReg will return the valid register, either from the COPY
8145         // or from the original source.
8146         assert(reg != REG_NA);
8147
8148         if (isMultiRegVar)
8149         {
8150             // Each field is passed in its own register, use the field types.
8151             regNumber  varReg      = lclNode->GetRegByIndex(i);
8152             unsigned   fieldLclNum = varDsc->lvFieldLclStart + i;
8153             LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(fieldLclNum);
8154             var_types  destType    = fieldVarDsc->TypeGet();
8155             if (varReg != REG_NA)
8156             {
8157                 hasRegs = true;
8158
8159                 // We may need a cross register-file copy here.
8160                 inst_Mov(destType, varReg, reg, /* canSkip */ true);
8161             }
8162             else
8163             {
8164                 varReg = REG_STK;
8165             }
8166             if ((varReg == REG_STK) || fieldVarDsc->IsAlwaysAliveInMemory())
8167             {
8168                 if (!lclNode->IsLastUse(i))
8169                 {
8170                     // A byte field passed in a long register should be written on the stack as a byte.
8171                     instruction storeIns = ins_StoreFromSrc(reg, destType);
8172                     GetEmitter()->emitIns_S_R(storeIns, emitTypeSize(destType), reg, fieldLclNum, 0);
8173                 }
8174             }
8175             fieldVarDsc->SetRegNum(varReg);
8176         }
8177         else
8178         {
8179 #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
8180             // should consider the padding field within a struct.
8181             offset = (offset % genTypeSize(srcType)) ? AlignUp(offset, genTypeSize(srcType)) : offset;
8182 #endif
8183             // Several fields could be passed in one register, copy using the register type.
8184             // It could rewrite memory outside of the fields but local on the stack are rounded to POINTER_SIZE so
8185             // it is safe to store a long register into a byte field as it is known that we have enough padding after.
8186             GetEmitter()->emitIns_S_R(ins_Store(srcType), emitTypeSize(srcType), reg, lclNum, offset);
8187             offset += genTypeSize(srcType);
8188
8189 #ifdef DEBUG
8190 #ifdef TARGET_64BIT
8191             assert(offset <= varDsc->lvSize());
8192 #else  // !TARGET_64BIT
8193             if (varTypeIsStruct(varDsc))
8194             {
8195                 assert(offset <= varDsc->lvSize());
8196             }
8197             else
8198             {
8199                 assert(varDsc->TypeGet() == TYP_LONG);
8200                 assert(offset <= genTypeSize(TYP_LONG));
8201             }
8202 #endif // !TARGET_64BIT
8203 #endif // DEBUG
8204         }
8205     }
8206
8207     // Update variable liveness.
8208     if (isMultiRegVar)
8209     {
8210         if (hasRegs)
8211         {
8212             genProduceReg(lclNode);
8213         }
8214         else
8215         {
8216             genUpdateLife(lclNode);
8217         }
8218     }
8219     else
8220     {
8221         genUpdateLife(lclNode);
8222         varDsc->SetRegNum(REG_STK);
8223     }
8224 }
8225
8226 //------------------------------------------------------------------------
8227 // genRegCopy: Produce code for a GT_COPY node.
8228 //
8229 // Arguments:
8230 //    tree - the GT_COPY node
8231 //
8232 // Notes:
8233 //    This will copy the register produced by this node's source, to
8234 //    the register allocated to this GT_COPY node.
8235 //    It has some special handling for these cases:
8236 //    - when the source and target registers are in different register files
8237 //      (note that this is *not* a conversion).
8238 //    - when the source is a lclVar whose home location is being moved to a new
8239 //      register (rather than just being copied for temporary use).
8240 //
8241 void CodeGen::genRegCopy(GenTree* treeNode)
8242 {
8243     assert(treeNode->OperGet() == GT_COPY);
8244     GenTree* op1 = treeNode->AsOp()->gtOp1;
8245
8246     if (op1->IsMultiRegNode())
8247     {
8248         // Register allocation assumes that any reload and copy are done in operand order.
8249         // That is, we can have:
8250         //    (reg0, reg1) = COPY(V0,V1) where V0 is in reg1 and V1 is in memory
8251         // The register allocation model assumes:
8252         //     First, V0 is moved to reg0 (v1 can't be in reg0 because it is still live, which would be a conflict).
8253         //     Then, V1 is moved to reg1
8254         // However, if we call genConsumeRegs on op1, it will do the reload of V1 before we do the copy of V0.
8255         // So we need to handle that case first.
8256         //
8257         // There should never be any circular dependencies, and we will check that here.
8258
8259         // GenTreeCopyOrReload only reports the highest index that has a valid register.
8260         // However, we need to ensure that we consume all the registers of the child node,
8261         // so we use its regCount.
8262         unsigned regCount = op1->GetMultiRegCount(compiler);
8263         assert(regCount <= MAX_MULTIREG_COUNT);
8264
8265         // First set the source registers as busy if they haven't been spilled.
8266         // (Note that this is just for verification that we don't have circular dependencies.)
8267         regMaskTP busyRegs = RBM_NONE;
8268         for (unsigned i = 0; i < regCount; ++i)
8269         {
8270             if ((op1->GetRegSpillFlagByIdx(i) & GTF_SPILLED) == 0)
8271             {
8272                 busyRegs |= genRegMask(op1->GetRegByIndex(i));
8273             }
8274         }
8275         for (unsigned i = 0; i < regCount; ++i)
8276         {
8277             regNumber sourceReg = op1->GetRegByIndex(i);
8278             // genRegCopy will consume the source register, perform any required reloads,
8279             // and will return either the register copied to, or the original register if there's no copy.
8280             regNumber targetReg = genRegCopy(treeNode, i);
8281             if (targetReg != sourceReg)
8282             {
8283                 regMaskTP targetRegMask = genRegMask(targetReg);
8284                 assert((busyRegs & targetRegMask) == 0);
8285                 // Clear sourceReg from the busyRegs, and add targetReg.
8286                 busyRegs &= ~genRegMask(sourceReg);
8287             }
8288             busyRegs |= genRegMask(targetReg);
8289         }
8290         return;
8291     }
8292
8293     regNumber srcReg     = genConsumeReg(op1);
8294     var_types targetType = treeNode->TypeGet();
8295     regNumber targetReg  = treeNode->GetRegNum();
8296     assert(srcReg != REG_NA);
8297     assert(targetReg != REG_NA);
8298     assert(targetType != TYP_STRUCT);
8299
8300     inst_Mov(targetType, targetReg, srcReg, /* canSkip */ false);
8301
8302     if (op1->IsLocal())
8303     {
8304         // The lclVar will never be a def.
8305         // If it is a last use, the lclVar will be killed by genConsumeReg(), as usual, and genProduceReg will
8306         // appropriately set the gcInfo for the copied value.
8307         // If not, there are two cases we need to handle:
8308         // - If this is a TEMPORARY copy (indicated by the GTF_VAR_DEATH flag) the variable
8309         //   will remain live in its original register.
8310         //   genProduceReg() will appropriately set the gcInfo for the copied value,
8311         //   and genConsumeReg will reset it.
8312         // - Otherwise, we need to update register info for the lclVar.
8313
8314         GenTreeLclVarCommon* lcl = op1->AsLclVarCommon();
8315         assert((lcl->gtFlags & GTF_VAR_DEF) == 0);
8316
8317         if ((lcl->gtFlags & GTF_VAR_DEATH) == 0 && (treeNode->gtFlags & GTF_VAR_DEATH) == 0)
8318         {
8319             LclVarDsc* varDsc = compiler->lvaGetDesc(lcl);
8320
8321             // If we didn't just spill it (in genConsumeReg, above), then update the register info
8322             if (varDsc->GetRegNum() != REG_STK)
8323             {
8324                 // The old location is dying
8325                 genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1));
8326
8327                 gcInfo.gcMarkRegSetNpt(genRegMask(op1->GetRegNum()));
8328
8329                 genUpdateVarReg(varDsc, treeNode);
8330
8331                 // Report the home change for this variable
8332                 varLiveKeeper->siUpdateVariableLiveRange(varDsc, lcl->GetLclNum());
8333
8334                 // The new location is going live
8335                 genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode));
8336             }
8337         }
8338     }
8339
8340     genProduceReg(treeNode);
8341 }
8342
8343 //------------------------------------------------------------------------
8344 // genRegCopy: Produce code for a single register of a multireg copy node.
8345 //
8346 // Arguments:
8347 //    tree          - The GT_COPY node
8348 //    multiRegIndex - The index of the register to be copied
8349 //
8350 // Notes:
8351 //    This will copy the corresponding register produced by this node's source, to
8352 //    the register allocated to the register specified by this GT_COPY node.
8353 //    A multireg copy doesn't support moving between register files, as the GT_COPY
8354 //    node does not retain separate types for each index.
8355 //    - when the source is a lclVar whose home location is being moved to a new
8356 //      register (rather than just being copied for temporary use).
8357 //
8358 // Return Value:
8359 //    Either the register copied to, or the original register if there's no copy.
8360 //
8361 regNumber CodeGen::genRegCopy(GenTree* treeNode, unsigned multiRegIndex)
8362 {
8363     assert(treeNode->OperGet() == GT_COPY);
8364     GenTree* op1 = treeNode->gtGetOp1();
8365     assert(op1->IsMultiRegNode());
8366
8367     GenTreeCopyOrReload* copyNode = treeNode->AsCopyOrReload();
8368     assert(copyNode->GetRegCount() <= MAX_MULTIREG_COUNT);
8369
8370     // Consume op1's register, which will perform any necessary reloads.
8371     genConsumeReg(op1, multiRegIndex);
8372
8373     regNumber sourceReg = op1->GetRegByIndex(multiRegIndex);
8374     regNumber targetReg = copyNode->GetRegNumByIdx(multiRegIndex);
8375     // GenTreeCopyOrReload only reports the highest index that has a valid register.
8376     // However there may be lower indices that have no valid register (i.e. the register
8377     // on the source is still valid at the consumer).
8378     if (targetReg != REG_NA)
8379     {
8380         // We shouldn't specify a no-op move.
8381         assert(sourceReg != targetReg);
8382         var_types type;
8383         if (op1->IsMultiRegLclVar())
8384         {
8385             LclVarDsc* parentVarDsc = compiler->lvaGetDesc(op1->AsLclVar());
8386             unsigned   fieldVarNum  = parentVarDsc->lvFieldLclStart + multiRegIndex;
8387             LclVarDsc* fieldVarDsc  = compiler->lvaGetDesc(fieldVarNum);
8388             type                    = fieldVarDsc->TypeGet();
8389             inst_Mov(type, targetReg, sourceReg, /* canSkip */ false);
8390             if (!op1->AsLclVar()->IsLastUse(multiRegIndex) && fieldVarDsc->GetRegNum() != REG_STK)
8391             {
8392                 // The old location is dying
8393                 genUpdateRegLife(fieldVarDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1));
8394                 gcInfo.gcMarkRegSetNpt(genRegMask(sourceReg));
8395                 genUpdateVarReg(fieldVarDsc, treeNode);
8396
8397                 // Report the home change for this variable
8398                 varLiveKeeper->siUpdateVariableLiveRange(fieldVarDsc, fieldVarNum);
8399
8400                 // The new location is going live
8401                 genUpdateRegLife(fieldVarDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode));
8402             }
8403         }
8404         else
8405         {
8406             type = op1->GetRegTypeByIndex(multiRegIndex);
8407             inst_Mov(type, targetReg, sourceReg, /* canSkip */ false);
8408             // We never spill after a copy, so to produce the single register, we simply need to
8409             // update the GC info for the defined register.
8410             gcInfo.gcMarkRegPtrVal(targetReg, type);
8411         }
8412         return targetReg;
8413     }
8414     else
8415     {
8416         return sourceReg;
8417     }
8418 }
8419
8420 #if defined(DEBUG) && defined(TARGET_XARCH)
8421
8422 //------------------------------------------------------------------------
8423 // genStackPointerCheck: Generate code to check the stack pointer against a saved value.
8424 // This is a debug check.
8425 //
8426 // Arguments:
8427 //    doStackPointerCheck - If true, do the stack pointer check, otherwise do nothing.
8428 //    lvaStackPointerVar  - The local variable number that holds the value of the stack pointer
8429 //                          we are comparing against.
8430 //    offset              - the offset from the stack pointer to expect
8431 //    regTmp              - register we can use for computation if `offset` != 0
8432 //
8433 // Return Value:
8434 //    None
8435 //
8436 void CodeGen::genStackPointerCheck(bool      doStackPointerCheck,
8437                                    unsigned  lvaStackPointerVar,
8438                                    ssize_t   offset,
8439                                    regNumber regTmp)
8440 {
8441     if (doStackPointerCheck)
8442     {
8443         assert(lvaStackPointerVar != BAD_VAR_NUM);
8444         assert(compiler->lvaGetDesc(lvaStackPointerVar)->lvDoNotEnregister);
8445         assert(compiler->lvaGetDesc(lvaStackPointerVar)->lvOnFrame);
8446
8447         if (offset != 0)
8448         {
8449             assert(regTmp != REG_NA);
8450             GetEmitter()->emitIns_Mov(INS_mov, EA_PTRSIZE, regTmp, REG_SPBASE, /* canSkip */ false);
8451             GetEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, regTmp, offset);
8452             GetEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, regTmp, lvaStackPointerVar, 0);
8453         }
8454         else
8455         {
8456             GetEmitter()->emitIns_S_R(INS_cmp, EA_PTRSIZE, REG_SPBASE, lvaStackPointerVar, 0);
8457         }
8458
8459         BasicBlock* sp_check = genCreateTempLabel();
8460         GetEmitter()->emitIns_J(INS_je, sp_check);
8461         instGen(INS_BREAKPOINT);
8462         genDefineTempLabel(sp_check);
8463     }
8464 }
8465
8466 #endif // defined(DEBUG) && defined(TARGET_XARCH)
8467
8468 unsigned CodeGenInterface::getCurrentStackLevel() const
8469 {
8470     return genStackLevel;
8471 }
8472
8473 #ifdef DEBUG
8474 //------------------------------------------------------------------------
8475 //                      VariableLiveRanges dumpers
8476 //------------------------------------------------------------------------
8477
8478 // Dump "VariableLiveRange" when code has not been generated and we don't have so the assembly native offset
8479 // but at least "emitLocation"s and "siVarLoc"
8480 void CodeGenInterface::VariableLiveKeeper::VariableLiveRange::dumpVariableLiveRange(
8481     const CodeGenInterface* codeGen) const
8482 {
8483     codeGen->dumpSiVarLoc(&m_VarLocation);
8484
8485     printf(" [");
8486     m_StartEmitLocation.Print(codeGen->GetCompiler()->compMethodID);
8487     printf(", ");
8488     if (m_EndEmitLocation.Valid())
8489     {
8490         m_EndEmitLocation.Print(codeGen->GetCompiler()->compMethodID);
8491     }
8492     else
8493     {
8494         printf("...");
8495     }
8496     printf("]");
8497 }
8498
8499 // Dump "VariableLiveRange" when code has been generated and we have the assembly native offset of each "emitLocation"
8500 void CodeGenInterface::VariableLiveKeeper::VariableLiveRange::dumpVariableLiveRange(
8501     emitter* emit, const CodeGenInterface* codeGen) const
8502 {
8503     assert(emit != nullptr);
8504
8505     // "VariableLiveRanges" are created setting its location ("m_VarLocation") and the initial native offset
8506     // ("m_StartEmitLocation")
8507     codeGen->dumpSiVarLoc(&m_VarLocation);
8508
8509     // If this is an open "VariableLiveRange", "m_EndEmitLocation" is non-valid and print -1
8510     UNATIVE_OFFSET endAssemblyOffset = m_EndEmitLocation.Valid() ? m_EndEmitLocation.CodeOffset(emit) : -1;
8511
8512     printf(" [%X, %X)", m_StartEmitLocation.CodeOffset(emit), m_EndEmitLocation.CodeOffset(emit));
8513 }
8514
8515 //------------------------------------------------------------------------
8516 //                      LiveRangeDumper
8517 //------------------------------------------------------------------------
8518 //------------------------------------------------------------------------
8519 // resetDumper: If the "liveRange" has its last "VariableLiveRange" closed, it makes
8520 //  the "LiveRangeDumper" points to end of "liveRange" (nullptr). In other case,
8521 //  it makes the "LiveRangeDumper" points to the last "VariableLiveRange" of
8522 //  "liveRange", which is opened.
8523 //
8524 // Arguments:
8525 //  liveRanges - the "LiveRangeList" of the "VariableLiveDescriptor" we want to
8526 //      update its "LiveRangeDumper".
8527 //
8528 // Notes:
8529 //  This method is expected to be called once a the code for a BasicBlock has been
8530 //  generated and all the new "VariableLiveRange"s of the variable during this block
8531 //  has been dumped.
8532 void CodeGenInterface::VariableLiveKeeper::LiveRangeDumper::resetDumper(const LiveRangeList* liveRanges)
8533 {
8534     // There must have reported something in order to reset
8535     assert(m_hasLiveRangestoDump);
8536
8537     if (liveRanges->back().m_EndEmitLocation.Valid())
8538     {
8539         // the last "VariableLiveRange" is closed and the variable
8540         // is no longer alive
8541         m_hasLiveRangestoDump = false;
8542     }
8543     else
8544     {
8545         // the last "VariableLiveRange" remains opened because it is
8546         // live at "BasicBlock"s "bbLiveOut".
8547         m_StartingLiveRange = liveRanges->backPosition();
8548     }
8549 }
8550
8551 //------------------------------------------------------------------------
8552 // setDumperStartAt: Make "LiveRangeDumper" instance points the last "VariableLiveRange"
8553 // added so we can starts dumping from there after the actual "BasicBlock"s code is generated.
8554 //
8555 // Arguments:
8556 //  liveRangeIt - an iterator to a position in "VariableLiveDescriptor::m_VariableLiveRanges"
8557 //
8558 // Return Value:
8559 //  A const pointer to the "LiveRangeList" containing all the "VariableLiveRange"s
8560 //  of the variable with index "varNum".
8561 //
8562 // Notes:
8563 //  "varNum" should be always a valid inde ("varnum" < "m_LiveDscCount")
8564 void CodeGenInterface::VariableLiveKeeper::LiveRangeDumper::setDumperStartAt(const LiveRangeListIterator liveRangeIt)
8565 {
8566     m_hasLiveRangestoDump = true;
8567     m_StartingLiveRange   = liveRangeIt;
8568 }
8569
8570 //------------------------------------------------------------------------
8571 // getStartForDump: Return an iterator to the first "VariableLiveRange" edited/added
8572 //  during the current "BasicBlock"
8573 //
8574 // Return Value:
8575 //  A LiveRangeListIterator to the first "VariableLiveRange" in "LiveRangeList" which
8576 //  was used during last "BasicBlock".
8577 //
8578 CodeGenInterface::VariableLiveKeeper::LiveRangeListIterator CodeGenInterface::VariableLiveKeeper::LiveRangeDumper::
8579     getStartForDump() const
8580 {
8581     return m_StartingLiveRange;
8582 }
8583
8584 //------------------------------------------------------------------------
8585 // hasLiveRangesToDump: Retutn whether at least a "VariableLiveRange" was alive during
8586 //  the current "BasicBlock"'s code generation
8587 //
8588 // Return Value:
8589 //  A boolean indicating indicating if there is at least a "VariableLiveRange"
8590 //  that has been used for the variable during last "BasicBlock".
8591 //
8592 bool CodeGenInterface::VariableLiveKeeper::LiveRangeDumper::hasLiveRangesToDump() const
8593 {
8594     return m_hasLiveRangestoDump;
8595 }
8596 #endif // DEBUG
8597
8598 //------------------------------------------------------------------------
8599 //                      VariableLiveDescriptor
8600 //------------------------------------------------------------------------
8601
8602 CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::VariableLiveDescriptor(CompAllocator allocator)
8603 {
8604     // Initialize an empty list
8605     m_VariableLiveRanges = new (allocator) LiveRangeList(allocator);
8606
8607     INDEBUG(m_VariableLifeBarrier = new (allocator) LiveRangeDumper(m_VariableLiveRanges));
8608 }
8609
8610 //------------------------------------------------------------------------
8611 // hasVariableLiveRangeOpen: Return true if the variable is still alive,
8612 //  false in other case.
8613 //
8614 bool CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::hasVariableLiveRangeOpen() const
8615 {
8616     return !m_VariableLiveRanges->empty() && !m_VariableLiveRanges->back().m_EndEmitLocation.Valid();
8617 }
8618
8619 //------------------------------------------------------------------------
8620 // getLiveRanges: Return the list of variable locations for this variable.
8621 //
8622 // Return Value:
8623 //  A const LiveRangeList* pointing to the first variable location if it has
8624 //  any or the end of the list in other case.
8625 //
8626 CodeGenInterface::VariableLiveKeeper::LiveRangeList* CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::
8627     getLiveRanges() const
8628 {
8629     return m_VariableLiveRanges;
8630 }
8631
8632 //------------------------------------------------------------------------
8633 // startLiveRangeFromEmitter: Report this variable as being born in "varLocation"
8634 //  since the instruction where "emit" is located.
8635 //
8636 // Arguments:
8637 //  varLocation  - the home of the variable.
8638 //  emit - an emitter* instance located at the first instruction from
8639 //  where "varLocation" becomes valid.
8640 //
8641 // Assumptions:
8642 //  This variable is being born so it should be dead.
8643 //
8644 // Notes:
8645 //  The position of "emit" matters to ensure intervals inclusive of the
8646 //  beginning and exclusive of the end.
8647 //
8648 void CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::startLiveRangeFromEmitter(
8649     CodeGenInterface::siVarLoc varLocation, emitter* emit) const
8650 {
8651     noway_assert(emit != nullptr);
8652
8653     // Is the first "VariableLiveRange" or the previous one has been closed so its "m_EndEmitLocation" is valid
8654     noway_assert(m_VariableLiveRanges->empty() || m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
8655
8656     if (!m_VariableLiveRanges->empty() &&
8657         siVarLoc::Equals(&varLocation, &(m_VariableLiveRanges->back().m_VarLocation)) &&
8658         m_VariableLiveRanges->back().m_EndEmitLocation.IsPreviousInsNum(emit))
8659     {
8660         JITDUMP("Extending debug range...\n");
8661
8662         // The variable is being born just after the instruction at which it died.
8663         // In this case, i.e. an update of the variable's value, we coalesce the live ranges.
8664         m_VariableLiveRanges->back().m_EndEmitLocation.Init();
8665     }
8666     else
8667     {
8668         JITDUMP("New debug range: %s\n",
8669                 m_VariableLiveRanges->empty()
8670                     ? "first"
8671                     : siVarLoc::Equals(&varLocation, &(m_VariableLiveRanges->back().m_VarLocation))
8672                           ? "new var or location"
8673                           : "not adjacent");
8674         // Creates new live range with invalid end
8675         m_VariableLiveRanges->emplace_back(varLocation, emitLocation(), emitLocation());
8676         m_VariableLiveRanges->back().m_StartEmitLocation.CaptureLocation(emit);
8677     }
8678
8679 #ifdef DEBUG
8680     if (!m_VariableLifeBarrier->hasLiveRangesToDump())
8681     {
8682         m_VariableLifeBarrier->setDumperStartAt(m_VariableLiveRanges->backPosition());
8683     }
8684 #endif // DEBUG
8685
8686     // startEmitLocationendEmitLocation has to be Valid and endEmitLocationendEmitLocation  not
8687     noway_assert(m_VariableLiveRanges->back().m_StartEmitLocation.Valid());
8688     noway_assert(!m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
8689 }
8690
8691 //------------------------------------------------------------------------
8692 // endLiveRangeAtEmitter: Report this variable as becoming dead since the
8693 //  instruction where "emit" is located.
8694 //
8695 // Arguments:
8696 //  emit - an emitter* instance located at the first instruction from
8697 //   this variable becomes dead.
8698 //
8699 // Assumptions:
8700 //  This variable is becoming dead so it should be alive.
8701 //
8702 // Notes:
8703 //  The position of "emit" matters to ensure intervals inclusive of the
8704 //  beginning and exclusive of the end.
8705 //
8706 void CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::endLiveRangeAtEmitter(emitter* emit) const
8707 {
8708     noway_assert(emit != nullptr);
8709     noway_assert(hasVariableLiveRangeOpen());
8710
8711     // Using [close, open) ranges so as to not compute the size of the last instruction
8712     m_VariableLiveRanges->back().m_EndEmitLocation.CaptureLocation(emit);
8713
8714     JITDUMP("Closing debug range.\n");
8715     // No m_EndEmitLocation has to be Valid
8716     noway_assert(m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
8717 }
8718
8719 //------------------------------------------------------------------------
8720 // UpdateLiveRangeAtEmitter: Report this variable as changing its variable
8721 //  home to "varLocation" since the instruction where "emit" is located.
8722 //
8723 // Arguments:
8724 //  varLocation  - the new variable location.
8725 //  emit - an emitter* instance located at the first instruction from
8726 //   where "varLocation" becomes valid.
8727 //
8728 // Assumptions:
8729 //  This variable is being born so it should be dead.
8730 //
8731 // Notes:
8732 //  The position of "emit" matters to ensure intervals inclusive of the
8733 //  beginning and exclusive of the end.
8734 //
8735 void CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::updateLiveRangeAtEmitter(
8736     CodeGenInterface::siVarLoc varLocation, emitter* emit) const
8737 {
8738     // This variable is changing home so it has been started before during this block
8739     noway_assert(m_VariableLiveRanges != nullptr && !m_VariableLiveRanges->empty());
8740
8741     // And its last m_EndEmitLocation has to be invalid
8742     noway_assert(!m_VariableLiveRanges->back().m_EndEmitLocation.Valid());
8743
8744     // If we are reporting again the same home, that means we are doing something twice?
8745     // noway_assert(! CodeGenInterface::siVarLoc::Equals(&m_VariableLiveRanges->back().m_VarLocation, varLocation));
8746
8747     // Close previous live range
8748     endLiveRangeAtEmitter(emit);
8749
8750     startLiveRangeFromEmitter(varLocation, emit);
8751 }
8752
8753 #ifdef DEBUG
8754 void CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::dumpAllRegisterLiveRangesForBlock(
8755     emitter* emit, const CodeGenInterface* codeGen) const
8756 {
8757     bool first = true;
8758     for (LiveRangeListIterator it = m_VariableLiveRanges->begin(); it != m_VariableLiveRanges->end(); it++)
8759     {
8760         if (!first)
8761         {
8762             printf("; ");
8763         }
8764         it->dumpVariableLiveRange(emit, codeGen);
8765         first = false;
8766     }
8767 }
8768
8769 void CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::dumpRegisterLiveRangesForBlockBeforeCodeGenerated(
8770     const CodeGenInterface* codeGen) const
8771 {
8772     bool first = true;
8773     for (LiveRangeListIterator it = m_VariableLifeBarrier->getStartForDump(); it != m_VariableLiveRanges->end(); it++)
8774     {
8775         if (!first)
8776         {
8777             printf("; ");
8778         }
8779         it->dumpVariableLiveRange(codeGen);
8780         first = false;
8781     }
8782 }
8783
8784 // Returns true if a live range for this variable has been recorded
8785 bool CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::hasVarLiveRangesToDump() const
8786 {
8787     return !m_VariableLiveRanges->empty();
8788 }
8789
8790 // Returns true if a live range for this variable has been recorded from last call to EndBlock
8791 bool CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::hasVarLiveRangesFromLastBlockToDump() const
8792 {
8793     return m_VariableLifeBarrier->hasLiveRangesToDump();
8794 }
8795
8796 // Reset the barrier so as to dump only next block changes on next block
8797 void CodeGenInterface::VariableLiveKeeper::VariableLiveDescriptor::endBlockLiveRanges()
8798 {
8799     // make "m_VariableLifeBarrier->m_StartingLiveRange" now points to nullptr for printing purposes
8800     m_VariableLifeBarrier->resetDumper(m_VariableLiveRanges);
8801 }
8802 #endif // DEBUG
8803
8804 //------------------------------------------------------------------------
8805 //                      VariableLiveKeeper
8806 //------------------------------------------------------------------------
8807 // Initialize structures for VariableLiveRanges
8808 void CodeGenInterface::initializeVariableLiveKeeper()
8809 {
8810     CompAllocator allocator = compiler->getAllocator(CMK_VariableLiveRanges);
8811
8812     int amountTrackedVariables = compiler->opts.compDbgInfo ? compiler->info.compLocalsCount : 0;
8813     int amountTrackedArgs      = compiler->opts.compDbgInfo ? compiler->info.compArgsCount : 0;
8814
8815     varLiveKeeper = new (allocator) VariableLiveKeeper(amountTrackedVariables, amountTrackedArgs, compiler, allocator);
8816 }
8817
8818 CodeGenInterface::VariableLiveKeeper* CodeGenInterface::getVariableLiveKeeper() const
8819 {
8820     return varLiveKeeper;
8821 };
8822
8823 //------------------------------------------------------------------------
8824 // VariableLiveKeeper: Create an instance of the object in charge of managing
8825 //  VariableLiveRanges and initialize the array "m_vlrLiveDsc".
8826 //
8827 // Arguments:
8828 //    totalLocalCount   - the count of args, special args and IL Local
8829 //      variables in the method.
8830 //    argsCount         - the count of args and special args in the method.
8831 //    compiler          - a compiler instance
8832 //
8833 CodeGenInterface::VariableLiveKeeper::VariableLiveKeeper(unsigned int  totalLocalCount,
8834                                                          unsigned int  argsCount,
8835                                                          Compiler*     comp,
8836                                                          CompAllocator allocator)
8837     : m_LiveDscCount(totalLocalCount)
8838     , m_LiveArgsCount(argsCount)
8839     , m_Compiler(comp)
8840     , m_LastBasicBlockHasBeenEmitted(false)
8841 {
8842     if (m_LiveDscCount > 0)
8843     {
8844         // Allocate memory for "m_vlrLiveDsc" and initialize each "VariableLiveDescriptor"
8845         m_vlrLiveDsc          = allocator.allocate<VariableLiveDescriptor>(m_LiveDscCount);
8846         m_vlrLiveDscForProlog = allocator.allocate<VariableLiveDescriptor>(m_LiveDscCount);
8847
8848         for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
8849         {
8850             new (m_vlrLiveDsc + varNum, jitstd::placement_t()) VariableLiveDescriptor(allocator);
8851             new (m_vlrLiveDscForProlog + varNum, jitstd::placement_t()) VariableLiveDescriptor(allocator);
8852         }
8853     }
8854 }
8855
8856 //------------------------------------------------------------------------
8857 // siStartOrCloseVariableLiveRange: Reports the given variable as beign born
8858 //  or becoming dead.
8859 //
8860 // Arguments:
8861 //    varDsc    - the variable for which a location changed will be reported
8862 //    varNum    - the index of the variable in the "compiler->lvaTable"
8863 //    isBorn    - whether the variable is being born from where the emitter is located.
8864 //    isDying   - whether the variable is dying from where the emitter is located.
8865 //
8866 // Assumptions:
8867 //    The emitter should be located on the first instruction from where is true that
8868 //    the variable becoming valid (when isBorn is true) or invalid (when isDying is true).
8869 //
8870 // Notes:
8871 //    This method is being called from treeLifeUpdater when the variable is being born,
8872 //    becoming dead, or both.
8873 //
8874 void CodeGenInterface::VariableLiveKeeper::siStartOrCloseVariableLiveRange(const LclVarDsc* varDsc,
8875                                                                            unsigned int     varNum,
8876                                                                            bool             isBorn,
8877                                                                            bool             isDying)
8878 {
8879     noway_assert(varDsc != nullptr);
8880
8881     // Only the variables that exists in the IL, "this", and special arguments
8882     // are reported.
8883     if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount)
8884     {
8885         if (isBorn && !isDying)
8886         {
8887             // "varDsc" is valid from this point
8888             siStartVariableLiveRange(varDsc, varNum);
8889         }
8890         if (isDying && !isBorn)
8891         {
8892             // this variable live range is no longer valid from this point
8893             siEndVariableLiveRange(varNum);
8894         }
8895     }
8896 }
8897
8898 //------------------------------------------------------------------------
8899 // siStartOrCloseVariableLiveRanges: Iterates the given set of variables
8900 //  calling "siStartOrCloseVariableLiveRange" with each one.
8901 //
8902 // Arguments:
8903 //    varsIndexSet    - the set of variables to report start/end "VariableLiveRange"
8904 //    isBorn    - whether the set is being born from where the emitter is located.
8905 //    isDying   - whether the set is dying from where the emitter is located.
8906 //
8907 // Assumptions:
8908 //    The emitter should be located on the first instruction from where is true that
8909 //    the variable becoming valid (when isBorn is true) or invalid (when isDying is true).
8910 //
8911 // Notes:
8912 //    This method is being called from treeLifeUpdater when a set of variables
8913 //    is being born, becoming dead, or both.
8914 //
8915 void CodeGenInterface::VariableLiveKeeper::siStartOrCloseVariableLiveRanges(VARSET_VALARG_TP varsIndexSet,
8916                                                                             bool             isBorn,
8917                                                                             bool             isDying)
8918 {
8919     if (m_Compiler->opts.compDbgInfo)
8920     {
8921         VarSetOps::Iter iter(m_Compiler, varsIndexSet);
8922         unsigned        varIndex = 0;
8923         while (iter.NextElem(&varIndex))
8924         {
8925             unsigned int     varNum = m_Compiler->lvaTrackedIndexToLclNum(varIndex);
8926             const LclVarDsc* varDsc = m_Compiler->lvaGetDesc(varNum);
8927             siStartOrCloseVariableLiveRange(varDsc, varNum, isBorn, isDying);
8928         }
8929     }
8930 }
8931
8932 //------------------------------------------------------------------------
8933 // siStartVariableLiveRange: Reports the given variable as being born.
8934 //
8935 // Arguments:
8936 //    varDsc    - the variable for which a location changed will be reported
8937 //    varNum    - the index of the variable to report home in lvLiveDsc
8938 //
8939 // Assumptions:
8940 //    The emitter should be pointing to the first instruction from where the VariableLiveRange is
8941 //    becoming valid.
8942 //    The given "varDsc" should have its VariableRangeLists initialized.
8943 //
8944 // Notes:
8945 //    This method should be called on every place a Variable is becoming alive.
8946 void CodeGenInterface::VariableLiveKeeper::siStartVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum)
8947 {
8948     noway_assert(varDsc != nullptr);
8949
8950     // Only the variables that exists in the IL, "this", and special arguments are reported, as long as they were
8951     // allocated.
8952     if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount && (varDsc->lvIsInReg() || varDsc->lvOnFrame))
8953     {
8954         // Build siVarLoc for this born "varDsc"
8955         CodeGenInterface::siVarLoc varLocation =
8956             m_Compiler->codeGen->getSiVarLoc(varDsc, m_Compiler->codeGen->getCurrentStackLevel());
8957
8958         VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum];
8959         // this variable live range is valid from this point
8960         varLiveDsc->startLiveRangeFromEmitter(varLocation, m_Compiler->GetEmitter());
8961     }
8962 }
8963
8964 //------------------------------------------------------------------------
8965 // siEndVariableLiveRange: Reports the variable as becoming dead.
8966 //
8967 // Arguments:
8968 //    varNum    - the index of the variable at m_vlrLiveDsc or lvaTable in that
8969 //       is becoming dead.
8970 //
8971 // Assumptions:
8972 //    The given variable should be alive.
8973 //    The emitter should be pointing to the first instruction from where the VariableLiveRange is
8974 //    becoming invalid.
8975 //
8976 // Notes:
8977 //    This method should be called on every place a Variable is becoming dead.
8978 void CodeGenInterface::VariableLiveKeeper::siEndVariableLiveRange(unsigned int varNum)
8979 {
8980     // Only the variables that exists in the IL, "this", and special arguments
8981     // will be reported.
8982
8983     // This method is being called from genUpdateLife, and that one is called after
8984     // code for BasicBlock have been generated, but the emitter has no longer
8985     // a valid IG so we don't report the close of a "VariableLiveRange" after code is
8986     // emitted.
8987
8988     if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount && !m_LastBasicBlockHasBeenEmitted &&
8989         m_vlrLiveDsc[varNum].hasVariableLiveRangeOpen())
8990     {
8991         // this variable live range is no longer valid from this point
8992         m_vlrLiveDsc[varNum].endLiveRangeAtEmitter(m_Compiler->GetEmitter());
8993     }
8994 }
8995
8996 //------------------------------------------------------------------------
8997 // siUpdateVariableLiveRange: Reports the change of variable location for the
8998 //  given variable.
8999 //
9000 // Arguments:
9001 //    varDsc    - the variable for which tis home has changed.
9002 //    varNum    - the index of the variable to report home in lvLiveDsc
9003 //
9004 // Assumptions:
9005 //    The given variable should be alive.
9006 //    The emitter should be pointing to the first instruction from where
9007 //    the new variable location is becoming valid.
9008 //
9009 void CodeGenInterface::VariableLiveKeeper::siUpdateVariableLiveRange(const LclVarDsc* varDsc, unsigned int varNum)
9010 {
9011     noway_assert(varDsc != nullptr);
9012
9013     // Only the variables that exists in the IL, "this", and special arguments
9014     // will be reported. This are locals and arguments, and are counted in
9015     // "info.compLocalsCount".
9016
9017     // This method is being called when the prolog is being generated, and
9018     // the emitter has no longer a valid IG so we don't report the close of
9019     //  a "VariableLiveRange" after code is emitted.
9020     if (m_Compiler->opts.compDbgInfo && varNum < m_LiveDscCount && !m_LastBasicBlockHasBeenEmitted)
9021     {
9022         // Build the location of the variable
9023         CodeGenInterface::siVarLoc siVarLoc =
9024             m_Compiler->codeGen->getSiVarLoc(varDsc, m_Compiler->codeGen->getCurrentStackLevel());
9025
9026         // Report the home change for this variable
9027         VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDsc[varNum];
9028         varLiveDsc->updateLiveRangeAtEmitter(siVarLoc, m_Compiler->GetEmitter());
9029     }
9030 }
9031
9032 //------------------------------------------------------------------------
9033 // siEndAllVariableLiveRange: Reports the set of variables as becoming dead.
9034 //
9035 // Arguments:
9036 //    newLife    - the set of variables that are becoming dead.
9037 //
9038 // Assumptions:
9039 //    All the variables in the set are alive.
9040 //
9041 // Notes:
9042 //    This method is called when the last block being generated to killed all
9043 //    the live variables and set a flag to avoid reporting variable locations for
9044 //    on next calls to method that update variable liveness.
9045 void CodeGenInterface::VariableLiveKeeper::siEndAllVariableLiveRange(VARSET_VALARG_TP varsToClose)
9046 {
9047     if (m_Compiler->opts.compDbgInfo)
9048     {
9049         if (m_Compiler->lvaTrackedCount > 0 || !m_Compiler->opts.OptimizationDisabled())
9050         {
9051             VarSetOps::Iter iter(m_Compiler, varsToClose);
9052             unsigned        varIndex = 0;
9053             while (iter.NextElem(&varIndex))
9054             {
9055                 unsigned int varNum = m_Compiler->lvaTrackedIndexToLclNum(varIndex);
9056                 siEndVariableLiveRange(varNum);
9057             }
9058         }
9059         else
9060         {
9061             // It seems we are jitting debug code, so we don't have variable
9062             //  liveness info
9063             siEndAllVariableLiveRange();
9064         }
9065     }
9066
9067     m_LastBasicBlockHasBeenEmitted = true;
9068 }
9069
9070 //------------------------------------------------------------------------
9071 // siEndAllVariableLiveRange: Reports all live variables as dead.
9072 //
9073 // Notes:
9074 //    This overload exists for the case we are jitting code compiled in
9075 //    debug mode. When that happen we don't have variable liveness info
9076 //    as "BaiscBlock::bbLiveIn" or "BaiscBlock::bbLiveOut" and there is no
9077 //    tracked variable.
9078 //
9079 void CodeGenInterface::VariableLiveKeeper::siEndAllVariableLiveRange()
9080 {
9081     // TODO: we can improve this keeping a set for the variables with
9082     // open VariableLiveRanges
9083
9084     for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
9085     {
9086         const VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
9087         if (varLiveDsc->hasVariableLiveRangeOpen())
9088         {
9089             siEndVariableLiveRange(varNum);
9090         }
9091     }
9092 }
9093
9094 //------------------------------------------------------------------------
9095 // getLiveRangesForVarForBody: Return the "VariableLiveRange" that correspond to
9096 //  the given "varNum".
9097 //
9098 // Arguments:
9099 //  varNum  - the index of the variable in m_vlrLiveDsc, which is the same as
9100 //      in lvaTable.
9101 //
9102 // Return Value:
9103 //  A const pointer to the list of variable locations reported for the variable.
9104 //
9105 // Assumptions:
9106 //  This variable should be an argument, a special argument or an IL local
9107 //  variable.
9108 CodeGenInterface::VariableLiveKeeper::LiveRangeList* CodeGenInterface::VariableLiveKeeper::getLiveRangesForVarForBody(
9109     unsigned int varNum) const
9110 {
9111     // There should be at least one variable for which its liveness is tracked
9112     noway_assert(varNum < m_LiveDscCount);
9113
9114     return m_vlrLiveDsc[varNum].getLiveRanges();
9115 }
9116
9117 //------------------------------------------------------------------------
9118 // getLiveRangesForVarForProlog: Return the "VariableLiveRange" that correspond to
9119 //  the given "varNum".
9120 //
9121 // Arguments:
9122 //  varNum  - the index of the variable in m_vlrLiveDsc, which is the same as
9123 //      in lvaTable.
9124 //
9125 // Return Value:
9126 //  A const pointer to the list of variable locations reported for the variable.
9127 //
9128 // Assumptions:
9129 //  This variable should be an argument, a special argument or an IL local
9130 //  variable.
9131 CodeGenInterface::VariableLiveKeeper::LiveRangeList* CodeGenInterface::VariableLiveKeeper::getLiveRangesForVarForProlog(
9132     unsigned int varNum) const
9133 {
9134     // There should be at least one variable for which its liveness is tracked
9135     noway_assert(varNum < m_LiveDscCount);
9136
9137     return m_vlrLiveDscForProlog[varNum].getLiveRanges();
9138 }
9139
9140 //------------------------------------------------------------------------
9141 // getLiveRangesCount: Returns the count of variable locations reported for the tracked
9142 //  variables, which are arguments, special arguments, and local IL variables.
9143 //
9144 // Return Value:
9145 //    size_t - the count of variable locations
9146 //
9147 // Notes:
9148 //    This method is being called from "genSetScopeInfo" to know the count of
9149 //    "varResultInfo" that should be created on eeSetLVcount.
9150 //
9151 size_t CodeGenInterface::VariableLiveKeeper::getLiveRangesCount() const
9152 {
9153     size_t liveRangesCount = 0;
9154
9155     if (m_Compiler->opts.compDbgInfo)
9156     {
9157         for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
9158         {
9159             for (int i = 0; i < 2; i++)
9160             {
9161                 VariableLiveDescriptor* varLiveDsc = (i == 0 ? m_vlrLiveDscForProlog : m_vlrLiveDsc) + varNum;
9162
9163                 if (m_Compiler->compMap2ILvarNum(varNum) != (unsigned int)ICorDebugInfo::UNKNOWN_ILNUM)
9164                 {
9165                     liveRangesCount += varLiveDsc->getLiveRanges()->size();
9166                 }
9167             }
9168         }
9169     }
9170     return liveRangesCount;
9171 }
9172
9173 //------------------------------------------------------------------------
9174 // psiStartVariableLiveRange: Reports the given variable as being born.
9175 //
9176 // Arguments:
9177 //  varLcation  - the variable location
9178 //  varNum      - the index of the variable in "compiler->lvaTable" or
9179 //      "VariableLivekeeper->m_vlrLiveDsc"
9180 //
9181 // Notes:
9182 //  This function is expected to be called from "psiBegProlog" during
9183 //  prolog code generation.
9184 //
9185 void CodeGenInterface::VariableLiveKeeper::psiStartVariableLiveRange(CodeGenInterface::siVarLoc varLocation,
9186                                                                      unsigned int               varNum)
9187 {
9188     // This descriptor has to correspond to a parameter. The first slots in lvaTable
9189     // are arguments and special arguments.
9190     noway_assert(varNum < m_LiveArgsCount);
9191
9192     VariableLiveDescriptor* varLiveDsc = &m_vlrLiveDscForProlog[varNum];
9193     varLiveDsc->startLiveRangeFromEmitter(varLocation, m_Compiler->GetEmitter());
9194 }
9195
9196 //------------------------------------------------------------------------
9197 // psiClosePrologVariableRanges: Report all the parameters as becoming dead.
9198 //
9199 // Notes:
9200 //  This function is expected to be called from preffix "psiEndProlog" after
9201 //  code for prolog has been generated.
9202 //
9203 void CodeGenInterface::VariableLiveKeeper::psiClosePrologVariableRanges()
9204 {
9205     noway_assert(m_LiveArgsCount <= m_LiveDscCount);
9206
9207     for (unsigned int varNum = 0; varNum < m_LiveArgsCount; varNum++)
9208     {
9209         VariableLiveDescriptor* varLiveDsc = m_vlrLiveDscForProlog + varNum;
9210
9211         if (varLiveDsc->hasVariableLiveRangeOpen())
9212         {
9213             varLiveDsc->endLiveRangeAtEmitter(m_Compiler->GetEmitter());
9214         }
9215     }
9216 }
9217
9218 #ifdef DEBUG
9219 void CodeGenInterface::VariableLiveKeeper::dumpBlockVariableLiveRanges(const BasicBlock* block)
9220 {
9221     assert(block != nullptr);
9222
9223     bool hasDumpedHistory = false;
9224
9225     printf("\nVariable Live Range History Dump for " FMT_BB "\n", block->bbNum);
9226
9227     if (m_Compiler->opts.compDbgInfo)
9228     {
9229         for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
9230         {
9231             VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
9232
9233             if (varLiveDsc->hasVarLiveRangesFromLastBlockToDump())
9234             {
9235                 hasDumpedHistory = true;
9236                 m_Compiler->gtDispLclVar(varNum, false);
9237                 printf(": ");
9238                 varLiveDsc->dumpRegisterLiveRangesForBlockBeforeCodeGenerated(m_Compiler->codeGen);
9239                 varLiveDsc->endBlockLiveRanges();
9240                 printf("\n");
9241             }
9242         }
9243     }
9244
9245     if (!hasDumpedHistory)
9246     {
9247         printf("..None..\n");
9248     }
9249 }
9250
9251 void CodeGenInterface::VariableLiveKeeper::dumpLvaVariableLiveRanges() const
9252 {
9253     bool hasDumpedHistory = false;
9254
9255     printf("VARIABLE LIVE RANGES:\n");
9256
9257     if (m_Compiler->opts.compDbgInfo)
9258     {
9259         for (unsigned int varNum = 0; varNum < m_LiveDscCount; varNum++)
9260         {
9261             VariableLiveDescriptor* varLiveDsc = m_vlrLiveDsc + varNum;
9262
9263             if (varLiveDsc->hasVarLiveRangesToDump())
9264             {
9265                 hasDumpedHistory = true;
9266                 m_Compiler->gtDispLclVar(varNum, false);
9267                 printf(": ");
9268                 varLiveDsc->dumpAllRegisterLiveRangesForBlock(m_Compiler->GetEmitter(), m_Compiler->codeGen);
9269                 printf("\n");
9270             }
9271         }
9272     }
9273
9274     if (!hasDumpedHistory)
9275     {
9276         printf("..None..\n");
9277     }
9278 }
9279 #endif // DEBUG
9280
9281 //-----------------------------------------------------------------------------
9282 // genPoisonFrame: Generate code that places a recognizable value into address exposed variables.
9283 //
9284 // Remarks:
9285 //   This function emits code to poison address exposed non-zero-inited local variables. We expect this function
9286 //   to be called when emitting code for the scratch BB that comes right after the prolog.
9287 //   The variables are poisoned using 0xcdcdcdcd.
9288 void CodeGen::genPoisonFrame(regMaskTP regLiveIn)
9289 {
9290     assert(compiler->compShouldPoisonFrame());
9291 #if defined(TARGET_XARCH)
9292     regNumber poisonValReg = REG_EAX;
9293     assert((regLiveIn & (RBM_EDI | RBM_ECX | RBM_EAX)) == 0);
9294 #else
9295     regNumber poisonValReg = REG_SCRATCH;
9296     assert((regLiveIn & (genRegMask(REG_SCRATCH) | RBM_ARG_0 | RBM_ARG_1 | RBM_ARG_2)) == 0);
9297 #endif
9298
9299 #ifdef TARGET_64BIT
9300     const ssize_t poisonVal = (ssize_t)0xcdcdcdcdcdcdcdcd;
9301 #else
9302     const ssize_t poisonVal = (ssize_t)0xcdcdcdcd;
9303 #endif
9304
9305     // The first time we need to poison something we will initialize a register to the largest immediate cccccccc that
9306     // we can fit.
9307     bool hasPoisonImm = false;
9308     for (unsigned varNum = 0; varNum < compiler->info.compLocalsCount; varNum++)
9309     {
9310         LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);
9311         if (varDsc->lvIsParam || varDsc->lvMustInit || !varDsc->IsAddressExposed())
9312         {
9313             continue;
9314         }
9315
9316         assert(varDsc->lvOnFrame);
9317
9318         unsigned int size = compiler->lvaLclSize(varNum);
9319         if ((size / TARGET_POINTER_SIZE) > 16)
9320         {
9321             // This will require more than 16 instructions, switch to rep stosd/memset call.
9322             CLANG_FORMAT_COMMENT_ANCHOR;
9323 #if defined(TARGET_XARCH)
9324             GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, REG_EDI, (int)varNum, 0);
9325             assert(size % 4 == 0);
9326             instGen_Set_Reg_To_Imm(EA_4BYTE, REG_ECX, size / 4);
9327             // On xarch we can leave the value in eax and only set eax once
9328             // since rep stosd does not kill eax.
9329             if (!hasPoisonImm)
9330             {
9331                 instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_EAX, poisonVal);
9332                 hasPoisonImm = true;
9333             }
9334             instGen(INS_r_stosd);
9335 #else
9336             GetEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, REG_ARG_0, (int)varNum, 0);
9337             instGen_Set_Reg_To_Imm(EA_4BYTE, REG_ARG_1, static_cast<char>(poisonVal));
9338             instGen_Set_Reg_To_Imm(EA_PTRSIZE, REG_ARG_2, size);
9339             genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN);
9340             // May kill REG_SCRATCH, so we need to reload it.
9341             hasPoisonImm = false;
9342 #endif
9343         }
9344         else
9345         {
9346             if (!hasPoisonImm)
9347             {
9348                 instGen_Set_Reg_To_Imm(EA_PTRSIZE, poisonValReg, poisonVal);
9349                 hasPoisonImm = true;
9350             }
9351
9352 // For 64-bit we check if the local is 8-byte aligned. For 32-bit, we assume everything is always 4-byte aligned.
9353 #ifdef TARGET_64BIT
9354             bool fpBased;
9355             int  addr = compiler->lvaFrameAddress((int)varNum, &fpBased);
9356 #else
9357             int addr     = 0;
9358 #endif
9359             int end = addr + (int)size;
9360             for (int offs = addr; offs < end;)
9361             {
9362 #ifdef TARGET_64BIT
9363                 if ((offs % 8) == 0 && end - offs >= 8)
9364                 {
9365                     GetEmitter()->emitIns_S_R(ins_Store(TYP_LONG), EA_8BYTE, REG_SCRATCH, (int)varNum, offs - addr);
9366                     offs += 8;
9367                     continue;
9368                 }
9369 #endif
9370
9371                 assert((offs % 4) == 0 && end - offs >= 4);
9372                 GetEmitter()->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, REG_SCRATCH, (int)varNum, offs - addr);
9373                 offs += 4;
9374             }
9375         }
9376     }
9377 }
9378
9379 //----------------------------------------------------------------------
9380 // genBitCast - Generate the instruction to move a value between register files
9381 //
9382 // Arguments
9383 //    targetType - the destination type
9384 //    targetReg  - the destination register
9385 //    srcType    - the source type
9386 //    srcReg     - the source register
9387 //
9388 void CodeGen::genBitCast(var_types targetType, regNumber targetReg, var_types srcType, regNumber srcReg)
9389 {
9390     const bool srcFltReg = varTypeUsesFloatReg(srcType);
9391     assert(srcFltReg == genIsValidFloatReg(srcReg));
9392
9393     const bool dstFltReg = varTypeUsesFloatReg(targetType);
9394     assert(dstFltReg == genIsValidFloatReg(targetReg));
9395
9396     inst_Mov(targetType, targetReg, srcReg, /* canSkip */ true);
9397 }
9398
9399 //----------------------------------------------------------------------
9400 // genCodeForBitCast - Generate code for a GT_BITCAST that is not contained
9401 //
9402 // Arguments
9403 //    treeNode - the GT_BITCAST for which we're generating code
9404 //
9405 void CodeGen::genCodeForBitCast(GenTreeOp* treeNode)
9406 {
9407     assert(treeNode->TypeGet() == genActualType(treeNode));
9408     regNumber targetReg  = treeNode->GetRegNum();
9409     var_types targetType = treeNode->TypeGet();
9410     GenTree*  op1        = treeNode->gtGetOp1();
9411     genConsumeRegs(op1);
9412
9413     if (op1->isContained())
9414     {
9415         assert(op1->OperIs(GT_LCL_VAR));
9416         unsigned    lclNum  = op1->AsLclVarCommon()->GetLclNum();
9417         instruction loadIns = ins_Load(targetType, compiler->isSIMDTypeLocalAligned(lclNum));
9418         GetEmitter()->emitIns_R_S(loadIns, emitTypeSize(targetType), targetReg, lclNum, 0);
9419     }
9420     else
9421     {
9422 #ifdef TARGET_ARM
9423         if (compiler->opts.compUseSoftFP && (targetType == TYP_LONG))
9424         {
9425             // This is a special arm-softFP case when a TYP_LONG node was introduced during lowering
9426             // for a call argument,  so it was not handled by decomposelongs phase as all other TYP_LONG nodes.
9427             // Example foo(double LclVar V01), LclVar V01 has to be passed in general registers r0, r1,
9428             // so lowering will add `BITCAST long(LclVar double V01)` and codegen has to support it here.
9429             const regNumber srcReg   = op1->GetRegNum();
9430             const regNumber otherReg = treeNode->AsMultiRegOp()->gtOtherReg;
9431             assert(otherReg != REG_NA);
9432             inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, srcReg, EA_8BYTE);
9433         }
9434         else
9435 #endif // TARGET_ARM
9436         {
9437             genBitCast(targetType, targetReg, op1->TypeGet(), op1->GetRegNum());
9438         }
9439     }
9440     genProduceReg(treeNode);
9441 }
9442
9443 //----------------------------------------------------------------------
9444 // genCanOmitNormalizationForBswap16:
9445 //   Small peephole to check if a bswap16 node can omit normalization.
9446 //
9447 // Arguments:
9448 //   tree - The BSWAP16 node
9449 //
9450 // Remarks:
9451 //   BSWAP16 nodes are required to zero extend the upper 16 bits, but since the
9452 //   importer always inserts a normalizing cast (either sign or zero extending)
9453 //   we almost never need to actually do this.
9454 //
9455 bool CodeGen::genCanOmitNormalizationForBswap16(GenTree* tree)
9456 {
9457     if (compiler->opts.OptimizationDisabled())
9458     {
9459         return false;
9460     }
9461
9462     assert(tree->OperIs(GT_BSWAP16));
9463     if ((tree->gtNext == nullptr) || !tree->gtNext->OperIs(GT_CAST))
9464     {
9465         return false;
9466     }
9467
9468     GenTreeCast* cast = tree->gtNext->AsCast();
9469     if (cast->gtOverflow() || (cast->CastOp() != tree))
9470     {
9471         return false;
9472     }
9473
9474     return (cast->gtCastType == TYP_USHORT) || (cast->gtCastType == TYP_SHORT);
9475 }
9476
9477 //----------------------------------------------------------------------
9478 // genCodeForReuseVal: Generate code for a node marked with re-using a register.
9479 //
9480 // Arguments:
9481 //   tree - The node marked with re-using a register
9482 //
9483 // Remarks:
9484 //   Generates nothing, except for when the node is a CNS_INT(0) where
9485 //   we will define a new label to propagate GC info. We want to do this
9486 //   because if the node is a CNS_INT(0) and is re-using a register,
9487 //   that register could have been used for a CNS_INT(ref null) that is GC
9488 //   tracked.
9489 //
9490 void CodeGen::genCodeForReuseVal(GenTree* treeNode)
9491 {
9492     assert(treeNode->IsReuseRegVal());
9493
9494     // For now, this is only used for constant nodes.
9495     assert(treeNode->OperIs(GT_CNS_INT, GT_CNS_DBL, GT_CNS_VEC));
9496     JITDUMP("  TreeNode is marked ReuseReg\n");
9497
9498     if (treeNode->IsIntegralConst(0) && GetEmitter()->emitCurIGnonEmpty())
9499     {
9500         genDefineTempLabel(genCreateTempLabel());
9501     }
9502 }