1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XX Classes to gather the Scope information from the local variable info. XX
11 XX Translates the given LocalVarTab from IL instruction offsets into XX
12 XX native code offsets. XX
14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
18 /******************************************************************************
21 * We break up blocks at the start and end IL ranges of the local variables.
22 * This is because IL offsets do not correspond exactly to native offsets
23 * except at block boundaries. No basic-blocks are deleted (not even
24 * unreachable), so there will not be any missing address-ranges, though the
25 * blocks themselves may not be ordered. (Also, internal blocks may be added).
26 * o At the start of each basic block, siBeginBlock() checks if any variables
27 * are coming in scope, and adds an open scope to siOpenScopeList if needed.
28 * o At the end of each basic block, siEndBlock() checks if any variables
29 * are going out of scope and moves the open scope from siOpenScopeLast
34 * We cannot break up the blocks as this will produce different code under
35 * the debugger. Instead we try to do a best effort.
36 * o At the start of each basic block, siBeginBlock() adds open scopes
37 * corresponding to block->bbLiveIn to siOpenScopeList. Also siUpdate()
38 * is called to close scopes for variables which are not live anymore.
39 * o siEndBlock() closes scopes for any variables which go out of range
40 * before bbCodeOffsEnd.
41 * o siCloseAllOpenScopes() closes any open scopes after all the blocks.
42 * This should only be needed if some basic block are deleted/out of order,
45 * o At every assignment to a variable, siCheckVarScope() adds an open scope
46 * for the variable being assigned to.
47 * o genChangeLife() calls siUpdate() which closes scopes for variables which
48 * are not live anymore.
50 ******************************************************************************
61 bool Compiler::siVarLoc::vlIsInReg(regNumber reg)
66 return (vlReg.vlrReg == reg);
68 return ((vlRegReg.vlrrReg1 == reg) || (vlRegReg.vlrrReg2 == reg));
70 return (vlRegStk.vlrsReg == reg);
72 return (vlStkReg.vlsrReg == reg);
80 assert(!"Bad locType");
85 bool Compiler::siVarLoc::vlIsOnStk(regNumber reg, signed offset)
93 actualReg = vlRegStk.vlrsStk.vlrssBaseReg;
94 if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
96 actualReg = REG_SPBASE;
98 return ((actualReg == reg) && (vlRegStk.vlrsStk.vlrssOffset == offset));
100 actualReg = vlStkReg.vlsrStk.vlsrsBaseReg;
101 if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
103 actualReg = REG_SPBASE;
105 return ((actualReg == reg) && (vlStkReg.vlsrStk.vlsrsOffset == offset));
107 actualReg = vlStk.vlsBaseReg;
108 if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
110 actualReg = REG_SPBASE;
112 return ((actualReg == reg) && (vlStk.vlsOffset == offset));
114 actualReg = vlStk2.vls2BaseReg;
115 if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
117 actualReg = REG_SPBASE;
119 return ((actualReg == reg) && ((vlStk2.vls2Offset == offset) || (vlStk2.vls2Offset == (offset - 4))));
128 assert(!"Bad locType");
133 /*============================================================================
135 * Implementation for ScopeInfo
138 * Whenever a variable comes into scope, add it to the list.
139 * When a varDsc goes dead, end its previous scope entry, and make a new one
140 * which is unavailable.
141 * When a varDsc goes live, end its previous un-available entry (if any) and
142 * set its new entry as available.
144 *============================================================================
147 /*****************************************************************************
150 * Creates a new scope and adds it to the Open scope list.
153 CodeGen::siScope* CodeGen::siNewScope(unsigned LVnum, unsigned varNum)
155 bool tracked = compiler->lvaTable[varNum].lvTracked;
156 unsigned varIndex = compiler->lvaTable[varNum].lvVarIndex;
160 siEndTrackedScope(varIndex);
163 siScope* newScope = (siScope*)compiler->compGetMem(sizeof(*newScope), CMK_SiScope);
165 newScope->scStartLoc.CaptureLocation(getEmitter());
166 assert(newScope->scStartLoc.Valid());
168 newScope->scEndLoc.Init();
170 newScope->scLVnum = LVnum;
171 newScope->scVarNum = varNum;
172 newScope->scNext = nullptr;
173 newScope->scStackLevel = genStackLevel; // used only by stack vars
175 siOpenScopeLast->scNext = newScope;
176 newScope->scPrev = siOpenScopeLast;
177 siOpenScopeLast = newScope;
181 siLatestTrackedScopes[varIndex] = newScope;
187 /*****************************************************************************
188 * siRemoveFromOpenScopeList
190 * Removes a scope from the open-scope list and puts it into the done-scope list
193 void CodeGen::siRemoveFromOpenScopeList(CodeGen::siScope* scope)
196 assert(scope->scEndLoc.Valid());
198 // Remove from open-scope list
200 scope->scPrev->scNext = scope->scNext;
203 scope->scNext->scPrev = scope->scPrev;
207 siOpenScopeLast = scope->scPrev;
210 // Add to the finished scope list. (Try to) filter out scopes of length 0.
212 if (scope->scStartLoc != scope->scEndLoc)
214 siScopeLast->scNext = scope;
220 /*----------------------------------------------------------------------------
221 * These functions end scopes given different types of parameters
222 *----------------------------------------------------------------------------
225 /*****************************************************************************
226 * For tracked vars, we don't need to search for the scope in the list as we
227 * have a pointer to the open scopes of all tracked variables.
230 void CodeGen::siEndTrackedScope(unsigned varIndex)
232 siScope* scope = siLatestTrackedScopes[varIndex];
238 scope->scEndLoc.CaptureLocation(getEmitter());
239 assert(scope->scEndLoc.Valid());
241 siRemoveFromOpenScopeList(scope);
243 siLatestTrackedScopes[varIndex] = nullptr;
246 /*****************************************************************************
247 * If we don't know that the variable is tracked, this function handles both
251 void CodeGen::siEndScope(unsigned varNum)
253 for (siScope* scope = siOpenScopeList.scNext; scope; scope = scope->scNext)
255 if (scope->scVarNum == varNum)
262 // At this point, we probably have a bad LocalVarTab
264 if (compiler->opts.compDbgCode)
266 // LocalVarTab is good?? If we reached here implies that we are in a
267 // bad state, so pretend that we don't have any scope info.
268 assert(!siVerifyLocalVarTab());
270 compiler->opts.compScopeInfo = false;
274 /*****************************************************************************
275 * If we have a handle to the siScope structure, we handle ending this scope
276 * differently than if we just had a variable number. This saves us searching
277 * the open-scope list again.
280 void CodeGen::siEndScope(siScope* scope)
282 scope->scEndLoc.CaptureLocation(getEmitter());
283 assert(scope->scEndLoc.Valid());
285 siRemoveFromOpenScopeList(scope);
287 LclVarDsc& lclVarDsc1 = compiler->lvaTable[scope->scVarNum];
288 if (lclVarDsc1.lvTracked)
290 siLatestTrackedScopes[lclVarDsc1.lvVarIndex] = nullptr;
294 /*****************************************************************************
295 * siVerifyLocalVarTab
297 * Checks the LocalVarTab for consistency. The VM may not have properly
298 * verified the LocalVariableTable.
303 bool CodeGen::siVerifyLocalVarTab()
305 // No entries with overlapping lives should have the same slot.
307 for (unsigned i = 0; i < compiler->info.compVarScopesCount; i++)
309 for (unsigned j = i + 1; j < compiler->info.compVarScopesCount; j++)
311 unsigned slot1 = compiler->info.compVarScopes[i].vsdVarNum;
312 unsigned beg1 = compiler->info.compVarScopes[i].vsdLifeBeg;
313 unsigned end1 = compiler->info.compVarScopes[i].vsdLifeEnd;
315 unsigned slot2 = compiler->info.compVarScopes[j].vsdVarNum;
316 unsigned beg2 = compiler->info.compVarScopes[j].vsdLifeBeg;
317 unsigned end2 = compiler->info.compVarScopes[j].vsdLifeEnd;
319 if (slot1 == slot2 && (end1 > beg2 && beg1 < end2))
331 /*============================================================================
332 * INTERFACE (public) Functions for ScopeInfo
333 *============================================================================
336 void CodeGen::siInit()
339 assert((unsigned)ICorDebugInfo::REGNUM_EAX == REG_EAX);
340 assert((unsigned)ICorDebugInfo::REGNUM_ECX == REG_ECX);
341 assert((unsigned)ICorDebugInfo::REGNUM_EDX == REG_EDX);
342 assert((unsigned)ICorDebugInfo::REGNUM_EBX == REG_EBX);
343 assert((unsigned)ICorDebugInfo::REGNUM_ESP == REG_ESP);
344 assert((unsigned)ICorDebugInfo::REGNUM_EBP == REG_EBP);
345 assert((unsigned)ICorDebugInfo::REGNUM_ESI == REG_ESI);
346 assert((unsigned)ICorDebugInfo::REGNUM_EDI == REG_EDI);
349 assert((unsigned)ICorDebugInfo::VLT_REG == Compiler::VLT_REG);
350 assert((unsigned)ICorDebugInfo::VLT_STK == Compiler::VLT_STK);
351 assert((unsigned)ICorDebugInfo::VLT_REG_REG == Compiler::VLT_REG_REG);
352 assert((unsigned)ICorDebugInfo::VLT_REG_STK == Compiler::VLT_REG_STK);
353 assert((unsigned)ICorDebugInfo::VLT_STK_REG == Compiler::VLT_STK_REG);
354 assert((unsigned)ICorDebugInfo::VLT_STK2 == Compiler::VLT_STK2);
355 assert((unsigned)ICorDebugInfo::VLT_FPSTK == Compiler::VLT_FPSTK);
356 assert((unsigned)ICorDebugInfo::VLT_FIXED_VA == Compiler::VLT_FIXED_VA);
357 assert((unsigned)ICorDebugInfo::VLT_COUNT == Compiler::VLT_COUNT);
358 assert((unsigned)ICorDebugInfo::VLT_INVALID == Compiler::VLT_INVALID);
360 /* ICorDebugInfo::VarLoc and siVarLoc should overlap exactly as we cast
361 * one to the other in eeSetLVinfo()
362 * Below is a "required but not sufficient" condition
365 assert(sizeof(ICorDebugInfo::VarLoc) == sizeof(Compiler::siVarLoc));
367 assert(compiler->opts.compScopeInfo);
369 siOpenScopeList.scNext = nullptr;
370 siOpenScopeLast = &siOpenScopeList;
371 siScopeLast = &siScopeList;
375 VarSetOps::AssignNoCopy(compiler, siLastLife, VarSetOps::MakeEmpty(compiler));
378 if (compiler->info.compVarScopesCount == 0)
383 #if FEATURE_EH_FUNCLETS
384 siInFuncletRegion = false;
385 #endif // FEATURE_EH_FUNCLETS
387 for (unsigned i = 0; i < lclMAX_TRACKED; i++)
389 siLatestTrackedScopes[i] = nullptr;
392 compiler->compResetScopeLists();
395 /*****************************************************************************
398 * Called at the beginning of code-gen for a block. Checks if any scopes
402 void CodeGen::siBeginBlock(BasicBlock* block)
404 assert(block != nullptr);
406 if (!compiler->opts.compScopeInfo)
411 if (compiler->info.compVarScopesCount == 0)
416 #if FEATURE_EH_FUNCLETS
417 if (siInFuncletRegion)
422 if (block->bbFlags & BBF_FUNCLET_BEG)
424 // For now, don't report any scopes in funclets. JIT64 doesn't.
425 siInFuncletRegion = true;
427 JITDUMP("Scope info: found beginning of funclet region at block BB%02u; ignoring following blocks\n",
432 #endif // FEATURE_EH_FUNCLETS
437 printf("\nScope info: begin block BB%02u, IL range ", block->bbNum);
438 block->dspBlockILRange();
443 unsigned beginOffs = block->bbCodeOffs;
445 if (beginOffs == BAD_IL_OFFSET)
447 JITDUMP("Scope info: ignoring block beginning\n");
451 if (!compiler->opts.compDbgCode)
453 /* For non-debuggable code */
455 // End scope of variables which are not live for this block
459 // Check that vars which are live on entry have an open scope
461 VarSetOps::Iter iter(compiler, block->bbLiveIn);
462 unsigned varIndex = 0;
463 while (iter.NextElem(&varIndex))
465 unsigned varNum = compiler->lvaTrackedToVarNum[varIndex];
466 // lvRefCnt may go down to 0 after liveness-analysis.
467 // So we need to check if this tracked variable is actually used.
468 if (!compiler->lvaTable[varNum].lvIsInReg() && !compiler->lvaTable[varNum].lvOnFrame)
470 assert(compiler->lvaTable[varNum].lvRefCnt == 0);
474 siCheckVarScope(varNum, beginOffs);
479 // For debuggable code, scopes can begin only on block boundaries.
480 // Check if there are any scopes on the current block's start boundary.
482 VarScopeDsc* varScope;
484 #if FEATURE_EH_FUNCLETS
486 // If we find a spot where the code offset isn't what we expect, because
487 // there is a gap, it might be because we've moved the funclets out of
488 // line. Catch up with the enter and exit scopes of the current block.
489 // Ignore the enter/exit scope changes of the missing scopes, which for
490 // funclets must be matched.
492 if (siLastEndOffs != beginOffs)
494 assert(beginOffs > 0);
495 assert(siLastEndOffs < beginOffs);
497 JITDUMP("Scope info: found offset hole. lastOffs=%u, currOffs=%u\n", siLastEndOffs, beginOffs);
500 while ((varScope = compiler->compGetNextEnterScope(beginOffs - 1, true)) != nullptr)
503 JITDUMP("Scope info: skipping enter scope, LVnum=%u\n", varScope->vsdLVnum);
507 while ((varScope = compiler->compGetNextExitScope(beginOffs - 1, true)) != nullptr)
510 JITDUMP("Scope info: skipping exit scope, LVnum=%u\n", varScope->vsdLVnum);
514 #else // FEATURE_EH_FUNCLETS
516 if (siLastEndOffs != beginOffs)
518 assert(siLastEndOffs < beginOffs);
522 #endif // FEATURE_EH_FUNCLETS
524 while ((varScope = compiler->compGetNextEnterScope(beginOffs)) != nullptr)
526 // brace-matching editor workaround for following line: (
527 JITDUMP("Scope info: opening scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, varScope->vsdLifeBeg,
528 varScope->vsdLifeEnd);
530 siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
533 LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum];
536 printf("Scope info: >> new scope, VarNum=%u, tracked? %s, VarIndex=%u, bbLiveIn=%s ",
537 varScope->vsdVarNum, lclVarDsc1->lvTracked ? "yes" : "no", lclVarDsc1->lvVarIndex,
538 VarSetOps::ToString(compiler, block->bbLiveIn));
539 dumpConvertedVarSet(compiler, block->bbLiveIn);
542 assert(!lclVarDsc1->lvTracked || VarSetOps::IsMember(compiler, block->bbLiveIn, lclVarDsc1->lvVarIndex));
555 /*****************************************************************************
558 * Called at the end of code-gen for a block. Any closing scopes are marked
559 * as such. Note that if we are collecting LocalVar info, scopes can
560 * only begin or end at block boundaries for debuggable code.
563 void CodeGen::siEndBlock(BasicBlock* block)
565 assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
567 #if FEATURE_EH_FUNCLETS
568 if (siInFuncletRegion)
572 #endif // FEATURE_EH_FUNCLETS
577 printf("\nScope info: end block BB%02u, IL range ", block->bbNum);
578 block->dspBlockILRange();
583 unsigned endOffs = block->bbCodeOffsEnd;
585 if (endOffs == BAD_IL_OFFSET)
587 JITDUMP("Scope info: ignoring block end\n");
591 // If non-debuggable code, find all scopes which end over this block
592 // and close them. For debuggable code, scopes will only end on block
595 VarScopeDsc* varScope;
596 while ((varScope = compiler->compGetNextExitScope(endOffs, !compiler->opts.compDbgCode)) != nullptr)
598 // brace-matching editor workaround for following line: (
599 JITDUMP("Scope info: ending scope, LVnum=%u [%03X..%03X)\n", varScope->vsdLVnum, varScope->vsdLifeBeg,
600 varScope->vsdLifeEnd);
602 unsigned varNum = varScope->vsdVarNum;
603 LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varNum];
607 if (lclVarDsc1->lvTracked)
609 siEndTrackedScope(lclVarDsc1->lvVarIndex);
617 siLastEndOffs = endOffs;
627 /*****************************************************************************
630 * Called at the start of basic blocks, and during code-gen of a block,
631 * for non-debuggable code, whenever the life of any tracked variable changes
632 * and the appropriate code has been generated. For debuggable code, variables are
633 * live over their entire scope, and so they go live or dead only on
636 void CodeGen::siUpdate()
638 if (!compiler->opts.compScopeInfo)
643 if (compiler->opts.compDbgCode)
648 if (compiler->info.compVarScopesCount == 0)
653 #if FEATURE_EH_FUNCLETS
654 if (siInFuncletRegion)
658 #endif // FEATURE_EH_FUNCLETS
660 VARSET_TP killed(VarSetOps::Diff(compiler, siLastLife, compiler->compCurLife));
661 assert(VarSetOps::IsSubset(compiler, killed, compiler->lvaTrackedVars));
663 VarSetOps::Iter iter(compiler, killed);
664 unsigned varIndex = 0;
665 while (iter.NextElem(&varIndex))
668 unsigned lclNum = compiler->lvaTrackedToVarNum[varIndex];
669 LclVarDsc* lclVar = &compiler->lvaTable[lclNum];
670 assert(lclVar->lvTracked);
673 siScope* scope = siLatestTrackedScopes[varIndex];
674 siEndTrackedScope(varIndex);
677 VarSetOps::Assign(compiler, siLastLife, compiler->compCurLife);
680 /*****************************************************************************
681 * In optimized code, we may not have access to gtLclVar.gtLclILoffs.
682 * So there may be ambiguity as to which entry in compiler->info.compVarScopes
683 * to use. We search the entire table and find the entry whose life
684 * begins closest to the given offset.
687 /*****************************************************************************
690 * For non-debuggable code, whenever we come across a GenTree which is an
691 * assignment to a local variable, this function is called to check if the
692 * variable has an open scope. Also, check if it has the correct LVnum.
695 void CodeGen::siCheckVarScope(unsigned varNum, IL_OFFSET offs)
697 assert(compiler->opts.compScopeInfo && !compiler->opts.compDbgCode && (compiler->info.compVarScopesCount > 0));
699 #if FEATURE_EH_FUNCLETS
700 if (siInFuncletRegion)
704 #endif // FEATURE_EH_FUNCLETS
706 if (offs == BAD_IL_OFFSET)
712 LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varNum];
714 // If there is an open scope corresponding to varNum, find it
716 if (lclVarDsc1->lvTracked)
718 scope = siLatestTrackedScopes[lclVarDsc1->lvVarIndex];
722 for (scope = siOpenScopeList.scNext; scope; scope = scope->scNext)
724 if (scope->scVarNum == varNum)
731 // Look up the compiler->info.compVarScopes[] to find the local var info for (varNum->lvSlotNum, offs)
732 VarScopeDsc* varScope = compiler->compFindLocalVar(varNum, offs);
733 if (varScope == nullptr)
738 // If the currently open scope does not have the correct LVnum, close it
739 // and create a new scope with this new LVnum
743 if (scope->scLVnum != varScope->vsdLVnum)
746 siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
751 siNewScope(varScope->vsdLVnum, varScope->vsdVarNum);
755 /*****************************************************************************
756 * siCloseAllOpenScopes
758 * For unreachable code, or optimized code with blocks reordered, there may be
759 * scopes left open at the end. Simply close them.
762 void CodeGen::siCloseAllOpenScopes()
764 assert(siOpenScopeList.scNext);
766 while (siOpenScopeList.scNext)
768 siEndScope(siOpenScopeList.scNext);
772 /*****************************************************************************
775 * Displays all the vars on the open-scope list
780 void CodeGen::siDispOpenScopes()
782 assert(compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0));
784 printf("Scope info: open scopes =\n");
786 if (siOpenScopeList.scNext == nullptr)
792 for (siScope* scope = siOpenScopeList.scNext; scope != nullptr; scope = scope->scNext)
794 VarScopeDsc* localVars = compiler->info.compVarScopes;
796 for (unsigned i = 0; i < compiler->info.compVarScopesCount; i++, localVars++)
798 if (localVars->vsdLVnum == scope->scLVnum)
800 const char* name = compiler->VarNameToStr(localVars->vsdName);
801 // brace-matching editor workaround for following line: (
802 printf(" %u (%s) [%03X..%03X)\n", localVars->vsdLVnum, name == nullptr ? "UNKNOWN" : name,
803 localVars->vsdLifeBeg, localVars->vsdLifeEnd);
813 /*============================================================================
815 * Implementation for PrologScopeInfo
817 *============================================================================
820 /*****************************************************************************
823 * Creates a new scope and adds it to the Open scope list.
826 CodeGen::psiScope* CodeGen::psiNewPrologScope(unsigned LVnum, unsigned slotNum)
828 psiScope* newScope = (psiScope*)compiler->compGetMem(sizeof(*newScope), CMK_SiScope);
830 newScope->scStartLoc.CaptureLocation(getEmitter());
831 assert(newScope->scStartLoc.Valid());
833 newScope->scEndLoc.Init();
835 newScope->scLVnum = LVnum;
836 newScope->scSlotNum = slotNum;
838 newScope->scNext = nullptr;
839 psiOpenScopeLast->scNext = newScope;
840 newScope->scPrev = psiOpenScopeLast;
841 psiOpenScopeLast = newScope;
846 /*****************************************************************************
849 * Remove the scope from the Open-scope list and add it to the finished-scopes
850 * list if its length is non-zero
853 void CodeGen::psiEndPrologScope(psiScope* scope)
855 scope->scEndLoc.CaptureLocation(getEmitter());
856 assert(scope->scEndLoc.Valid());
858 // Remove from open-scope list
859 scope->scPrev->scNext = scope->scNext;
862 scope->scNext->scPrev = scope->scPrev;
866 psiOpenScopeLast = scope->scPrev;
869 // Add to the finished scope list.
870 // If the length is zero, it means that the prolog is empty. In that case,
871 // CodeGen::genSetScopeInfo will report the liveness of all arguments
872 // as spanning the first instruction in the method, so that they can
873 // at least be inspected on entry to the method.
874 if (scope->scStartLoc != scope->scEndLoc || scope->scStartLoc.IsOffsetZero())
876 psiScopeLast->scNext = scope;
877 psiScopeLast = scope;
882 /*============================================================================
883 * INTERFACE (protected) Functions for PrologScopeInfo
884 *============================================================================
887 //------------------------------------------------------------------------
888 // psSetScopeOffset: Set the offset of the newScope to the offset of the LslVar
891 // 'newScope' the new scope object whose offset is to be set to the lclVarDsc offset.
892 // 'lclVarDsc' is an op that will now be contained by its parent.
895 void CodeGen::psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc)
897 newScope->scRegister = false;
898 newScope->u2.scBaseReg = REG_SPBASE;
900 #ifdef _TARGET_AMD64_
901 // scOffset = offset from caller SP - REGSIZE_BYTES
902 // TODO-Cleanup - scOffset needs to be understood. For now just matching with the existing definition.
903 newScope->u2.scOffset =
904 compiler->lvaToCallerSPRelativeOffset(lclVarDsc->lvStkOffs, lclVarDsc->lvFramePointerBased) + REGSIZE_BYTES;
905 #else // !_TARGET_AMD64_
906 if (doubleAlignOrFramePointerUsed())
908 // REGSIZE_BYTES - for the pushed value of EBP
909 newScope->u2.scOffset = lclVarDsc->lvStkOffs - REGSIZE_BYTES;
913 newScope->u2.scOffset = lclVarDsc->lvStkOffs - genTotalFrameSize();
915 #endif // !_TARGET_AMD64_
918 /*============================================================================
919 * INTERFACE (public) Functions for PrologScopeInfo
920 *============================================================================
923 /*****************************************************************************
926 * Initializes the PrologScopeInfo, and creates open scopes for all the
927 * parameters of the method.
930 void CodeGen::psiBegProlog()
932 assert(compiler->compGeneratingProlog);
934 VarScopeDsc* varScope;
936 psiOpenScopeList.scNext = nullptr;
937 psiOpenScopeLast = &psiOpenScopeList;
938 psiScopeLast = &psiScopeList;
941 compiler->compResetScopeLists();
943 while ((varScope = compiler->compGetNextEnterScope(0)) != nullptr)
945 LclVarDsc* lclVarDsc1 = &compiler->lvaTable[varScope->vsdVarNum];
947 if (!lclVarDsc1->lvIsParam)
952 psiScope* newScope = psiNewPrologScope(varScope->vsdLVnum, varScope->vsdVarNum);
954 if (lclVarDsc1->lvIsRegArg)
956 bool isStructHandled = false;
957 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
958 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
959 if (varTypeIsStruct(lclVarDsc1))
961 CORINFO_CLASS_HANDLE typeHnd = lclVarDsc1->lvVerTypeInfo.GetClassHandle();
962 assert(typeHnd != nullptr);
963 compiler->eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
964 if (structDesc.passedInRegisters)
966 regNumber regNum = REG_NA;
967 regNumber otherRegNum = REG_NA;
968 for (unsigned nCnt = 0; nCnt < structDesc.eightByteCount; nCnt++)
970 unsigned len = structDesc.eightByteSizes[nCnt];
971 var_types regType = TYP_UNDEF;
975 regNum = lclVarDsc1->lvArgReg;
979 otherRegNum = lclVarDsc1->lvOtherArgReg;
983 assert(false && "Invalid eightbyte number.");
986 regType = compiler->GetEightByteType(structDesc, nCnt);
988 regType = compiler->mangleVarArgsType(regType);
989 assert(genMapRegNumToRegArgNum((nCnt == 0 ? regNum : otherRegNum), regType) != (unsigned)-1);
993 newScope->scRegister = true;
994 newScope->u1.scRegNum = (regNumberSmall)regNum;
995 newScope->u1.scOtherReg = (regNumberSmall)otherRegNum;
999 // Stack passed argument. Get the offset from the caller's frame.
1000 psSetScopeOffset(newScope, lclVarDsc1);
1003 isStructHandled = true;
1005 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
1006 if (!isStructHandled)
1009 var_types regType = compiler->mangleVarArgsType(lclVarDsc1->TypeGet());
1010 if (lclVarDsc1->lvIsHfaRegArg())
1012 regType = lclVarDsc1->GetHfaType();
1014 assert(genMapRegNumToRegArgNum(lclVarDsc1->lvArgReg, regType) != (unsigned)-1);
1017 newScope->scRegister = true;
1018 newScope->u1.scRegNum = (regNumberSmall)lclVarDsc1->lvArgReg;
1023 psSetScopeOffset(newScope, lclVarDsc1);
1028 /*****************************************************************************
1029 Enable this macro to get accurate prolog information for every instruction
1030 in the prolog. However, this is overkill as nobody steps through the
1031 disassembly of the prolog. Even if they do they will not expect rich debug info.
1033 We still report all the arguments at the very start of the method so that
1034 the user can see the arguments at the very start of the method (offset=0).
1036 Disabling this decreased the debug maps in mscorlib by 10% (01/2003)
1040 #define ACCURATE_PROLOG_DEBUG_INFO
1043 /*****************************************************************************
1044 * psiAdjustStackLevel
1046 * When ESP changes, all scopes relative to ESP have to be updated.
1049 void CodeGen::psiAdjustStackLevel(unsigned size)
1051 if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1056 assert(compiler->compGeneratingProlog);
1058 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1062 // walk the list backwards
1063 // Works as psiEndPrologScope does not change scPrev
1064 for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1066 if (scope->scRegister)
1068 assert(compiler->lvaTable[scope->scSlotNum].lvIsRegArg);
1071 assert(scope->u2.scBaseReg == REG_SPBASE);
1073 psiScope* newScope = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1074 newScope->scRegister = false;
1075 newScope->u2.scBaseReg = REG_SPBASE;
1076 newScope->u2.scOffset = scope->u2.scOffset + size;
1078 psiEndPrologScope(scope);
1081 #endif // ACCURATE_PROLOG_DEBUG_INFO
1084 /*****************************************************************************
1087 * For EBP-frames, the parameters are accessed via ESP on entry to the function,
1088 * but via EBP right after a "mov ebp,esp" instruction
1091 void CodeGen::psiMoveESPtoEBP()
1093 if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1098 assert(compiler->compGeneratingProlog);
1099 assert(doubleAlignOrFramePointerUsed());
1101 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1105 // walk the list backwards
1106 // Works as psiEndPrologScope does not change scPrev
1107 for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1109 if (scope->scRegister)
1111 assert(compiler->lvaTable[scope->scSlotNum].lvIsRegArg);
1114 assert(scope->u2.scBaseReg == REG_SPBASE);
1116 psiScope* newScope = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1117 newScope->scRegister = false;
1118 newScope->u2.scBaseReg = REG_FPBASE;
1119 newScope->u2.scOffset = scope->u2.scOffset;
1121 psiEndPrologScope(scope);
1124 #endif // ACCURATE_PROLOG_DEBUG_INFO
1127 /*****************************************************************************
1130 * Called when a parameter is loaded into its assigned register from the stack,
1131 * or when parameters are moved around due to circular dependancy.
1132 * If reg != REG_NA, then the parameter is being moved into its assigned
1133 * register, else it may be being moved to a temp register.
1136 void CodeGen::psiMoveToReg(unsigned varNum, regNumber reg, regNumber otherReg)
1138 assert(compiler->compGeneratingProlog);
1140 if (!compiler->opts.compScopeInfo)
1145 if (compiler->info.compVarScopesCount == 0)
1150 assert((int)varNum >= 0); // It's not a spill temp number.
1151 assert(compiler->lvaTable[varNum].lvIsInReg());
1153 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1155 /* If reg!=REG_NA, the parameter is part of a cirular dependancy, and is
1156 * being moved through temp register "reg".
1157 * If reg==REG_NA, it is being moved to its assigned register.
1161 // Grab the assigned registers.
1163 reg = compiler->lvaTable[varNum].lvRegNum;
1164 otherReg = compiler->lvaTable[varNum].lvOtherReg;
1169 // walk the list backwards
1170 // Works as psiEndPrologScope does not change scPrev
1171 for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1173 if (scope->scSlotNum != compiler->lvaTable[varNum].lvSlotNum)
1176 psiScope* newScope = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1177 newScope->scRegister = true;
1178 newScope->u1.scRegNum = reg;
1179 newScope->u1.scOtherReg = otherReg;
1181 psiEndPrologScope(scope);
1185 // May happen if a parameter does not have an entry in the LocalVarTab
1186 // But assert() just in case it is because of something else.
1187 assert(varNum == compiler->info.compRetBuffArg ||
1188 !"Parameter scope not found (Assert doesnt always indicate error)");
1190 #endif // ACCURATE_PROLOG_DEBUG_INFO
1193 /*****************************************************************************
1194 * CodeGen::psiMoveToStack
1196 * A incoming register-argument is being moved to its final home on the stack
1197 * (ie. all adjustements to {F/S}PBASE have been made
1200 void CodeGen::psiMoveToStack(unsigned varNum)
1202 if (!compiler->opts.compScopeInfo || (compiler->info.compVarScopesCount == 0))
1207 assert(compiler->compGeneratingProlog);
1208 assert(compiler->lvaTable[varNum].lvIsRegArg);
1209 assert(!compiler->lvaTable[varNum].lvRegister);
1211 #ifdef ACCURATE_PROLOG_DEBUG_INFO
1215 // walk the list backwards
1216 // Works as psiEndPrologScope does not change scPrev
1217 for (scope = psiOpenScopeLast; scope != &psiOpenScopeList; scope = scope->scPrev)
1219 if (scope->scSlotNum != compiler->lvaTable[varNum].lvSlotNum)
1222 /* The param must be currently sitting in the register in which it
1224 assert(scope->scRegister);
1225 assert(scope->u1.scRegNum == compiler->lvaTable[varNum].lvArgReg);
1227 psiScope* newScope = psiNewPrologScope(scope->scLVnum, scope->scSlotNum);
1228 newScope->scRegister = false;
1229 newScope->u2.scBaseReg = (compiler->lvaTable[varNum].lvFramePointerBased) ? REG_FPBASE : REG_SPBASE;
1230 newScope->u2.scOffset = compiler->lvaTable[varNum].lvStkOffs;
1232 psiEndPrologScope(scope);
1236 // May happen if a parameter does not have an entry in the LocalVarTab
1237 // But assert() just in case it is because of something else.
1238 assert(varNum == compiler->info.compRetBuffArg ||
1239 !"Parameter scope not found (Assert doesnt always indicate error)");
1241 #endif // ACCURATE_PROLOG_DEBUG_INFO
1244 /*****************************************************************************
1248 void CodeGen::psiEndProlog()
1250 assert(compiler->compGeneratingProlog);
1253 for (scope = psiOpenScopeList.scNext; scope; scope = psiOpenScopeList.scNext)
1255 psiEndPrologScope(scope);