//-------------------------------------------------------------------------
// scope info for the variables
- void genSetScopeInfo(unsigned which,
- UNATIVE_OFFSET startOffs,
- UNATIVE_OFFSET length,
- unsigned varNum,
- unsigned LVnum,
- bool avail,
- Compiler::siVarLoc& loc);
+ void genSetScopeInfo(unsigned which,
+ UNATIVE_OFFSET startOffs,
+ UNATIVE_OFFSET length,
+ unsigned varNum,
+ unsigned LVnum,
+ bool avail,
+ siVarLoc* varLoc);
void genSetScopeInfo();
siScope* scNext;
};
+ // Returns a "siVarLoc" instance representing the place where the variable lives base on
+ // varDsc and scope description.
+ CodeGenInterface::siVarLoc getSiVarLoc(const LclVarDsc* varDsc, const siScope* scope) const;
+
siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
unsigned siScopeCnt;
psiScope* scPrev;
psiScope* scNext;
+
+ // Returns a "siVarLoc" instance representing the place where the variable lives base on
+ // psiScope properties.
+ CodeGenInterface::siVarLoc getSiVarLoc() const;
};
psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
struct TrnslLocalVarInfo
{
- unsigned tlviVarNum;
- unsigned tlviLVnum;
- VarName tlviName;
- UNATIVE_OFFSET tlviStartPC;
- size_t tlviLength;
- bool tlviAvailable;
- Compiler::siVarLoc tlviVarLoc;
+ unsigned tlviVarNum;
+ unsigned tlviLVnum;
+ VarName tlviName;
+ UNATIVE_OFFSET tlviStartPC;
+ size_t tlviLength;
+ bool tlviAvailable;
+ siVarLoc tlviVarLoc;
};
// Array of scopes of LocalVars in terms of native code
endOffs++;
}
- Compiler::siVarLoc varLoc;
+ siVarLoc varLoc = scopeP->getSiVarLoc();
- if (scopeP->scRegister)
- {
- varLoc.vlType = Compiler::VLT_REG;
- varLoc.vlReg.vlrReg = (regNumber)scopeP->u1.scRegNum;
- }
- else
- {
- varLoc.vlType = Compiler::VLT_STK;
- varLoc.vlStk.vlsBaseReg = (regNumber)scopeP->u2.scBaseReg;
- varLoc.vlStk.vlsOffset = scopeP->u2.scOffset;
- }
-
- genSetScopeInfo(i, startOffs, endOffs - startOffs, varNum, scopeP->scLVnum, true, varLoc);
+ genSetScopeInfo(i, startOffs, endOffs - startOffs, varNum, scopeP->scLVnum, true, &varLoc);
}
// Record the scopes for the rest of the method.
noway_assert(scopeL->scStartLoc != scopeL->scEndLoc);
- // For stack vars, find the base register, and offset
-
- regNumber baseReg;
- signed offset = compiler->lvaTable[scopeL->scVarNum].lvStkOffs;
-
- if (!compiler->lvaTable[scopeL->scVarNum].lvFramePointerBased)
- {
- baseReg = REG_SPBASE;
- offset += scopeL->scStackLevel;
- }
- else
- {
- baseReg = REG_FPBASE;
- }
-
- // Now fill in the varLoc
-
- Compiler::siVarLoc varLoc;
-
- // TODO-Review: This only works for always-enregistered variables. With LSRA, a variable might be in a register
- // for part of its lifetime, or in different registers for different parts of its lifetime.
- // This should only matter for non-debug code, where we do variable enregistration.
- // We should store the ranges of variable enregistration in the scope table.
- if (compiler->lvaTable[scopeL->scVarNum].lvIsInReg())
- {
- var_types type = genActualType(compiler->lvaTable[scopeL->scVarNum].TypeGet());
- switch (type)
- {
- case TYP_INT:
- case TYP_REF:
- case TYP_BYREF:
-#ifdef _TARGET_64BIT_
- case TYP_LONG:
-#endif // _TARGET_64BIT_
-
- varLoc.vlType = Compiler::VLT_REG;
- varLoc.vlReg.vlrReg = compiler->lvaTable[scopeL->scVarNum].lvRegNum;
- break;
-
-#ifndef _TARGET_64BIT_
- case TYP_LONG:
-#if !CPU_HAS_FP_SUPPORT
- case TYP_DOUBLE:
-#endif
-
- if (compiler->lvaTable[scopeL->scVarNum].lvOtherReg != REG_STK)
- {
- varLoc.vlType = Compiler::VLT_REG_REG;
- varLoc.vlRegReg.vlrrReg1 = compiler->lvaTable[scopeL->scVarNum].lvRegNum;
- varLoc.vlRegReg.vlrrReg2 = compiler->lvaTable[scopeL->scVarNum].lvOtherReg;
- }
- else
- {
- varLoc.vlType = Compiler::VLT_REG_STK;
- varLoc.vlRegStk.vlrsReg = compiler->lvaTable[scopeL->scVarNum].lvRegNum;
- varLoc.vlRegStk.vlrsStk.vlrssBaseReg = baseReg;
- if (!isFramePointerUsed() && varLoc.vlRegStk.vlrsStk.vlrssBaseReg == REG_SPBASE)
- {
- varLoc.vlRegStk.vlrsStk.vlrssBaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
- }
- varLoc.vlRegStk.vlrsStk.vlrssOffset = offset + sizeof(int);
- }
- break;
-#endif // !_TARGET_64BIT_
-
-#ifdef _TARGET_64BIT_
-
- case TYP_FLOAT:
- case TYP_DOUBLE:
- // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15,
- // so no XMM registers can get debug information.
- varLoc.vlType = Compiler::VLT_REG_FP;
- varLoc.vlReg.vlrReg = compiler->lvaTable[scopeL->scVarNum].lvRegNum;
- break;
-
-#else // !_TARGET_64BIT_
-
-#if CPU_HAS_FP_SUPPORT
- case TYP_FLOAT:
- case TYP_DOUBLE:
- if (isFloatRegType(type))
- {
- varLoc.vlType = Compiler::VLT_FPSTK;
- varLoc.vlFPstk.vlfReg = compiler->lvaTable[scopeL->scVarNum].lvRegNum;
- }
- break;
-#endif // CPU_HAS_FP_SUPPORT
-
-#endif // !_TARGET_64BIT_
-
-#ifdef FEATURE_SIMD
- case TYP_SIMD8:
- case TYP_SIMD12:
- case TYP_SIMD16:
- case TYP_SIMD32:
- varLoc.vlType = Compiler::VLT_REG_FP;
-
- // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15,
- // so no XMM registers can get debug information.
- //
- // Note: Need to initialize vlrReg field, otherwise during jit dump hitting an assert
- // in eeDispVar() --> getRegName() that regNumber is valid.
- varLoc.vlReg.vlrReg = compiler->lvaTable[scopeL->scVarNum].lvRegNum;
- break;
-#endif // FEATURE_SIMD
-
- default:
- noway_assert(!"Invalid type");
- }
- }
- else
- {
- assert(offset != BAD_STK_OFFS);
- LclVarDsc* varDsc = compiler->lvaTable + scopeL->scVarNum;
- switch (genActualType(varDsc->TypeGet()))
- {
- case TYP_INT:
- case TYP_REF:
- case TYP_BYREF:
- case TYP_FLOAT:
- case TYP_STRUCT:
- case TYP_BLK: // Needed because of the TYP_BLK stress mode
-#ifdef FEATURE_SIMD
- case TYP_SIMD8:
- case TYP_SIMD12:
- case TYP_SIMD16:
- case TYP_SIMD32:
-#endif
-#ifdef _TARGET_64BIT_
- case TYP_LONG:
- case TYP_DOUBLE:
-#endif // _TARGET_64BIT_
-#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
- // In the AMD64 ABI we are supposed to pass a struct by reference when its
- // size is not 1, 2, 4 or 8 bytes in size. During fgMorph, the compiler modifies
- // the IR to comply with the ABI and therefore changes the type of the lclVar
- // that holds the struct from TYP_STRUCT to TYP_BYREF but it gives us a hint that
- // this is still a struct by setting the lvIsTemp flag.
- // The same is true for ARM64 and structs > 16 bytes.
- // (See Compiler::fgMarkImplicitByRefArgs in Morph.cpp for further detail)
- // Now, the VM expects a special enum for these type of local vars: VLT_STK_BYREF
- // to accomodate for this situation.
- if (varDsc->lvType == TYP_BYREF && varDsc->lvIsTemp)
- {
- assert(varDsc->lvIsParam);
- varLoc.vlType = Compiler::VLT_STK_BYREF;
- }
- else
-#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
- {
- varLoc.vlType = Compiler::VLT_STK;
- }
- varLoc.vlStk.vlsBaseReg = baseReg;
- varLoc.vlStk.vlsOffset = offset;
- if (!isFramePointerUsed() && varLoc.vlStk.vlsBaseReg == REG_SPBASE)
- {
- varLoc.vlStk.vlsBaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
- }
- break;
-
-#ifndef _TARGET_64BIT_
- case TYP_LONG:
- case TYP_DOUBLE:
- varLoc.vlType = Compiler::VLT_STK2;
- varLoc.vlStk2.vls2BaseReg = baseReg;
- varLoc.vlStk2.vls2Offset = offset;
- if (!isFramePointerUsed() && varLoc.vlStk2.vls2BaseReg == REG_SPBASE)
- {
- varLoc.vlStk2.vls2BaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
- }
- break;
-#endif // !_TARGET_64BIT_
-
- default:
- noway_assert(!"Invalid type");
- }
- }
+ LclVarDsc* varDsc = compiler->lvaGetDesc(scopeL->scVarNum);
+ siVarLoc varLoc = getSiVarLoc(varDsc, scopeL);
genSetScopeInfo(psiScopeCnt + i, startOffs, endOffs - startOffs, scopeL->scVarNum, scopeL->scLVnum,
- scopeL->scAvailable, varLoc);
+ scopeL->scAvailable, &varLoc);
}
compiler->eeSetLVdone();
// length - the length of this scope
// varNum - the lclVar for this scope info
// LVnum
-// avail
-// varLoc
+// avail - a bool indicating if it has a home
+// varLoc - the position (reg or stack) of the variable
//
// Notes:
// Called for every scope info piece to record by the main genSetScopeInfo()
-void CodeGen::genSetScopeInfo(unsigned which,
- UNATIVE_OFFSET startOffs,
- UNATIVE_OFFSET length,
- unsigned varNum,
- unsigned LVnum,
- bool avail,
- Compiler::siVarLoc& varLoc)
+void CodeGen::genSetScopeInfo(unsigned which,
+ UNATIVE_OFFSET startOffs,
+ UNATIVE_OFFSET length,
+ unsigned varNum,
+ unsigned LVnum,
+ bool avail,
+ siVarLoc* varLoc)
{
// We need to do some mapping while reporting back these variables.
if (compiler->info.compIsVarArgs && varNum != compiler->lvaVarargsHandleArg &&
varNum < compiler->info.compArgsCount && !compiler->lvaTable[varNum].lvIsRegArg)
{
- noway_assert(varLoc.vlType == Compiler::VLT_STK || varLoc.vlType == Compiler::VLT_STK2);
+ noway_assert(varLoc->vlType == VLT_STK || varLoc->vlType == VLT_STK2);
// All stack arguments (except the varargs handle) have to be
// accessed via the varargs cookie. Discard generated info,
noway_assert(offset < stkArgSize);
offset = stkArgSize - offset;
- varLoc.vlType = Compiler::VLT_FIXED_VA;
- varLoc.vlFixedVarArg.vlfvOffset = offset;
+ varLoc->vlType = VLT_FIXED_VA;
+ varLoc->vlFixedVarArg.vlfvOffset = offset;
}
#endif // _TARGET_X86_
tlvi.tlviStartPC = startOffs;
tlvi.tlviLength = length;
tlvi.tlviAvailable = avail;
- tlvi.tlviVarLoc = varLoc;
+ tlvi.tlviVarLoc = *varLoc;
#endif // DEBUG
public:
virtual void siUpdate() = 0;
+ /* These are the different addressing modes used to access a local var.
+ * The JIT has to report the location of the locals back to the EE
+ * for debugging purposes.
+ */
+
+ enum siVarLocType
+ {
+ VLT_REG,
+ VLT_REG_BYREF, // this type is currently only used for value types on X64
+ VLT_REG_FP,
+ VLT_STK,
+ VLT_STK_BYREF, // this type is currently only used for value types on X64
+ VLT_REG_REG,
+ VLT_REG_STK,
+ VLT_STK_REG,
+ VLT_STK2,
+ VLT_FPSTK,
+ VLT_FIXED_VA,
+
+ VLT_COUNT,
+ VLT_INVALID
+ };
+
+ struct siVarLoc
+ {
+ siVarLocType vlType;
+
+ union {
+ // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc)
+ // eg. EAX
+ // VLT_REG_BYREF -- the specified register contains the address of the variable
+ // eg. [EAX]
+
+ struct
+ {
+ regNumber vlrReg;
+ } vlReg;
+
+ // VLT_STK -- Any 32 bit value which is on the stack
+ // eg. [ESP+0x20], or [EBP-0x28]
+ // VLT_STK_BYREF -- the specified stack location contains the address of the variable
+ // eg. mov EAX, [ESP+0x20]; [EAX]
+
+ struct
+ {
+ regNumber vlsBaseReg;
+ NATIVE_OFFSET vlsOffset;
+ } vlStk;
+
+ // VLT_REG_REG -- TYP_LONG/TYP_DOUBLE with both DWords enregistered
+ // eg. RBM_EAXEDX
+
+ struct
+ {
+ regNumber vlrrReg1;
+ regNumber vlrrReg2;
+ } vlRegReg;
+
+ // VLT_REG_STK -- Partly enregistered TYP_LONG/TYP_DOUBLE
+ // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] }
+
+ struct
+ {
+ regNumber vlrsReg;
+
+ struct
+ {
+ regNumber vlrssBaseReg;
+ NATIVE_OFFSET vlrssOffset;
+ } vlrsStk;
+ } vlRegStk;
+
+ // VLT_STK_REG -- Partly enregistered TYP_LONG/TYP_DOUBLE
+ // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX }
+
+ struct
+ {
+ struct
+ {
+ regNumber vlsrsBaseReg;
+ NATIVE_OFFSET vlsrsOffset;
+ } vlsrStk;
+
+ regNumber vlsrReg;
+ } vlStkReg;
+
+ // VLT_STK2 -- Any 64 bit value which is on the stack, in 2 successsive DWords
+ // eg 2 DWords at [ESP+0x10]
+
+ struct
+ {
+ regNumber vls2BaseReg;
+ NATIVE_OFFSET vls2Offset;
+ } vlStk2;
+
+ // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack)
+ // eg. ST(3). Actually it is ST("FPstkHeight - vpFpStk")
+
+ struct
+ {
+ unsigned vlfReg;
+ } vlFPstk;
+
+ // VLT_FIXED_VA -- fixed argument of a varargs function.
+ // The argument location depends on the size of the variable
+ // arguments (...). Inspecting the VARARGS_HANDLE indicates the
+ // location of the first arg. This argument can then be accessed
+ // relative to the position of the first arg
+
+ struct
+ {
+ unsigned vlfvOffset;
+ } vlFixedVarArg;
+
+ // VLT_MEMORY
+
+ struct
+ {
+ void* rpValue; // pointer to the in-process
+ // location of the value.
+ } vlMemory;
+ };
+
+ // Helper functions
+
+ bool vlIsInReg(regNumber reg);
+ bool vlIsOnStk(regNumber reg, signed offset);
+
+ siVarLoc(const LclVarDsc* varDsc, regNumber baseReg, int offset, bool isFramePointerUsed);
+ siVarLoc(){};
+
+ private:
+ // Fill "siVarLoc" properties indicating the register position of the variable
+ // using "LclVarDsc" and "baseReg"/"offset" if it has a part in the stack (x64 bit float or long).
+ void siFillRegisterVarLoc(
+ const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed);
+
+ // Fill "siVarLoc" properties indicating the register position of the variable
+ // using "LclVarDsc" and "baseReg"/"offset" if it is a variable with part in a register and
+ // part in thestack
+ void siFillStackVarLoc(
+ const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed);
+ };
+
#ifdef LATE_DISASM
public:
virtual const char* siRegVarName(size_t offs, size_t size, unsigned reg) = 0;
*/
public:
- /* These are the different addressing modes used to access a local var.
- * The JIT has to report the location of the locals back to the EE
- * for debugging purposes.
- */
-
- enum siVarLocType
- {
- VLT_REG,
- VLT_REG_BYREF, // this type is currently only used for value types on X64
- VLT_REG_FP,
- VLT_STK,
- VLT_STK_BYREF, // this type is currently only used for value types on X64
- VLT_REG_REG,
- VLT_REG_STK,
- VLT_STK_REG,
- VLT_STK2,
- VLT_FPSTK,
- VLT_FIXED_VA,
-
- VLT_COUNT,
- VLT_INVALID
- };
-
- struct siVarLoc
- {
- siVarLocType vlType;
-
- union {
- // VLT_REG/VLT_REG_FP -- Any pointer-sized enregistered value (TYP_INT, TYP_REF, etc)
- // eg. EAX
- // VLT_REG_BYREF -- the specified register contains the address of the variable
- // eg. [EAX]
-
- struct
- {
- regNumber vlrReg;
- } vlReg;
-
- // VLT_STK -- Any 32 bit value which is on the stack
- // eg. [ESP+0x20], or [EBP-0x28]
- // VLT_STK_BYREF -- the specified stack location contains the address of the variable
- // eg. mov EAX, [ESP+0x20]; [EAX]
-
- struct
- {
- regNumber vlsBaseReg;
- NATIVE_OFFSET vlsOffset;
- } vlStk;
-
- // VLT_REG_REG -- TYP_LONG/TYP_DOUBLE with both DWords enregistered
- // eg. RBM_EAXEDX
-
- struct
- {
- regNumber vlrrReg1;
- regNumber vlrrReg2;
- } vlRegReg;
-
- // VLT_REG_STK -- Partly enregistered TYP_LONG/TYP_DOUBLE
- // eg { LowerDWord=EAX UpperDWord=[ESP+0x8] }
-
- struct
- {
- regNumber vlrsReg;
-
- struct
- {
- regNumber vlrssBaseReg;
- NATIVE_OFFSET vlrssOffset;
- } vlrsStk;
- } vlRegStk;
-
- // VLT_STK_REG -- Partly enregistered TYP_LONG/TYP_DOUBLE
- // eg { LowerDWord=[ESP+0x8] UpperDWord=EAX }
-
- struct
- {
- struct
- {
- regNumber vlsrsBaseReg;
- NATIVE_OFFSET vlsrsOffset;
- } vlsrStk;
-
- regNumber vlsrReg;
- } vlStkReg;
-
- // VLT_STK2 -- Any 64 bit value which is on the stack, in 2 successsive DWords
- // eg 2 DWords at [ESP+0x10]
-
- struct
- {
- regNumber vls2BaseReg;
- NATIVE_OFFSET vls2Offset;
- } vlStk2;
-
- // VLT_FPSTK -- enregisterd TYP_DOUBLE (on the FP stack)
- // eg. ST(3). Actually it is ST("FPstkHeight - vpFpStk")
-
- struct
- {
- unsigned vlfReg;
- } vlFPstk;
-
- // VLT_FIXED_VA -- fixed argument of a varargs function.
- // The argument location depends on the size of the variable
- // arguments (...). Inspecting the VARARGS_HANDLE indicates the
- // location of the first arg. This argument can then be accessed
- // relative to the position of the first arg
-
- struct
- {
- unsigned vlfvOffset;
- } vlFixedVarArg;
-
- // VLT_MEMORY
-
- struct
- {
- void* rpValue; // pointer to the in-process
- // location of the value.
- } vlMemory;
- };
-
- // Helper functions
-
- bool vlIsInReg(regNumber reg);
- bool vlIsOnStk(regNumber reg, signed offset);
- };
-
- /*************************************************************************/
-
-public:
// Get handles
void eeGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
struct VarResultInfo
{
- UNATIVE_OFFSET startOffset;
- UNATIVE_OFFSET endOffset;
- DWORD varNumber;
- siVarLoc loc;
+ UNATIVE_OFFSET startOffset;
+ UNATIVE_OFFSET endOffset;
+ DWORD varNumber;
+ CodeGenInterface::siVarLoc loc;
} * eeVars;
void eeSetLVcount(unsigned count);
- void eeSetLVinfo(unsigned which,
- UNATIVE_OFFSET startOffs,
- UNATIVE_OFFSET length,
- unsigned varNum,
- unsigned LVnum,
- VarName namex,
- bool avail,
- const siVarLoc& loc);
+ void eeSetLVinfo(unsigned which,
+ UNATIVE_OFFSET startOffs,
+ UNATIVE_OFFSET length,
+ unsigned varNum,
+ unsigned LVnum,
+ VarName namex,
+ bool avail,
+ const CodeGenInterface::siVarLoc* loc);
void eeSetLVdone();
#ifdef DEBUG
return codeGen->getEmitter();
}
- bool isFramePointerUsed()
+ bool isFramePointerUsed() const
{
return codeGen->isFramePointerUsed();
}
}
}
-void Compiler::eeSetLVinfo(unsigned which,
- UNATIVE_OFFSET startOffs,
- UNATIVE_OFFSET length,
- unsigned varNum,
- unsigned LVnum,
- VarName name,
- bool avail,
- const Compiler::siVarLoc& varLoc)
+void Compiler::eeSetLVinfo(unsigned which,
+ UNATIVE_OFFSET startOffs,
+ UNATIVE_OFFSET length,
+ unsigned varNum,
+ unsigned LVnum,
+ VarName name,
+ bool avail,
+ const CodeGenInterface::siVarLoc* varLoc)
{
- // ICorDebugInfo::VarLoc and Compiler::siVarLoc have to overlap
+ // ICorDebugInfo::VarLoc and CodeGenInterface::siVarLoc have to overlap
// This is checked in siInit()
assert(opts.compScopeInfo);
eeVars[which].startOffset = startOffs;
eeVars[which].endOffset = startOffs + length;
eeVars[which].varNumber = varNum;
- eeVars[which].loc = varLoc;
+ eeVars[which].loc = *varLoc;
}
}
printf("%3d(%10s) : From %08Xh to %08Xh, in ", var->varNumber,
(VarNameToStr(name) == nullptr) ? "UNKNOWN" : VarNameToStr(name), var->startOffset, var->endOffset);
- switch ((Compiler::siVarLocType)var->loc.vlType)
+ switch ((CodeGenInterface::siVarLocType)var->loc.vlType)
{
- case VLT_REG:
- case VLT_REG_BYREF:
- case VLT_REG_FP:
+ case CodeGenInterface::VLT_REG:
+ case CodeGenInterface::VLT_REG_BYREF:
+ case CodeGenInterface::VLT_REG_FP:
printf("%s", getRegName(var->loc.vlReg.vlrReg));
- if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
+ if (var->loc.vlType == (ICorDebugInfo::VarLocType)CodeGenInterface::VLT_REG_BYREF)
{
printf(" byref");
}
break;
- case VLT_STK:
- case VLT_STK_BYREF:
+ case CodeGenInterface::VLT_STK:
+ case CodeGenInterface::VLT_STK_BYREF:
if ((int)var->loc.vlStk.vlsBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
printf("%s[%d] (1 slot)", getRegName(var->loc.vlStk.vlsBaseReg), var->loc.vlStk.vlsOffset);
{
printf(STR_SPBASE "'[%d] (1 slot)", var->loc.vlStk.vlsOffset);
}
- if (var->loc.vlType == (ICorDebugInfo::VarLocType)VLT_REG_BYREF)
+ if (var->loc.vlType == (ICorDebugInfo::VarLocType)CodeGenInterface::VLT_REG_BYREF)
{
printf(" byref");
}
break;
#ifndef _TARGET_AMD64_
- case VLT_REG_REG:
+ case CodeGenInterface::VLT_REG_REG:
printf("%s-%s", getRegName(var->loc.vlRegReg.vlrrReg1), getRegName(var->loc.vlRegReg.vlrrReg2));
break;
- case VLT_REG_STK:
+ case CodeGenInterface::VLT_REG_STK:
if ((int)var->loc.vlRegStk.vlrsStk.vlrssBaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
printf("%s-%s[%d]", getRegName(var->loc.vlRegStk.vlrsReg),
}
break;
- case VLT_STK_REG:
+ case CodeGenInterface::VLT_STK_REG:
unreached(); // unexpected
- case VLT_STK2:
+ case CodeGenInterface::VLT_STK2:
if ((int)var->loc.vlStk2.vls2BaseReg != (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
printf("%s[%d] (2 slots)", getRegName(var->loc.vlStk2.vls2BaseReg), var->loc.vlStk2.vls2Offset);
}
break;
- case VLT_FPSTK:
+ case CodeGenInterface::VLT_FPSTK:
printf("ST(L-%d)", var->loc.vlFPstk.vlfReg);
break;
- case VLT_FIXED_VA:
+ case CodeGenInterface::VLT_FIXED_VA:
printf("fxd_va[%d]", var->loc.vlFixedVarArg.vlfvOffset);
break;
#endif // !_TARGET_AMD64_
#include "emit.h"
#include "codegen.h"
-bool Compiler::siVarLoc::vlIsInReg(regNumber reg)
+bool CodeGenInterface::siVarLoc::vlIsInReg(regNumber reg)
{
switch (vlType)
{
- case VLT_REG:
+ case CodeGenInterface::VLT_REG:
return (vlReg.vlrReg == reg);
- case VLT_REG_REG:
+ case CodeGenInterface::VLT_REG_REG:
return ((vlRegReg.vlrrReg1 == reg) || (vlRegReg.vlrrReg2 == reg));
- case VLT_REG_STK:
+ case CodeGenInterface::VLT_REG_STK:
return (vlRegStk.vlrsReg == reg);
- case VLT_STK_REG:
+ case CodeGenInterface::VLT_STK_REG:
return (vlStkReg.vlsrReg == reg);
- case VLT_STK:
- case VLT_STK2:
- case VLT_FPSTK:
+ case CodeGenInterface::VLT_STK:
+ case CodeGenInterface::VLT_STK2:
+ case CodeGenInterface::VLT_FPSTK:
return false;
default:
}
}
-bool Compiler::siVarLoc::vlIsOnStk(regNumber reg, signed offset)
+bool CodeGenInterface::siVarLoc::vlIsOnStk(regNumber reg, signed offset)
{
regNumber actualReg;
switch (vlType)
{
- case VLT_REG_STK:
+ case CodeGenInterface::VLT_REG_STK:
actualReg = vlRegStk.vlrsStk.vlrssBaseReg;
if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
actualReg = REG_SPBASE;
}
return ((actualReg == reg) && (vlRegStk.vlrsStk.vlrssOffset == offset));
- case VLT_STK_REG:
+ case CodeGenInterface::VLT_STK_REG:
actualReg = vlStkReg.vlsrStk.vlsrsBaseReg;
if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
actualReg = REG_SPBASE;
}
return ((actualReg == reg) && (vlStkReg.vlsrStk.vlsrsOffset == offset));
- case VLT_STK:
+ case CodeGenInterface::VLT_STK:
actualReg = vlStk.vlsBaseReg;
if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
actualReg = REG_SPBASE;
}
return ((actualReg == reg) && (vlStk.vlsOffset == offset));
- case VLT_STK2:
+ case CodeGenInterface::VLT_STK2:
actualReg = vlStk2.vls2BaseReg;
if ((int)actualReg == (int)ICorDebugInfo::REGNUM_AMBIENT_SP)
{
}
return ((actualReg == reg) && ((vlStk2.vls2Offset == offset) || (vlStk2.vls2Offset == (offset - 4))));
- case VLT_REG:
- case VLT_REG_FP:
- case VLT_REG_REG:
- case VLT_FPSTK:
+ case CodeGenInterface::VLT_REG:
+ case CodeGenInterface::VLT_REG_FP:
+ case CodeGenInterface::VLT_REG_REG:
+ case CodeGenInterface::VLT_FPSTK:
return false;
default:
}
}
+//------------------------------------------------------------------------
+// siVarLoc: Non-empty constructor of siVarLoc struct
+// Arguments:
+// varDsc - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
+// baseReg - a "regNumber" use as a base for the offset.
+// offset - a signed amount of bytes distance from "baseReg" for the position of the variable.
+// isFramePointerUsed - a boolean variable
+//
+// Notes:
+// Called for every psiScope in "psiScopeList" codegen.h
+CodeGenInterface::siVarLoc::siVarLoc(const LclVarDsc* varDsc, regNumber baseReg, int offset, bool isFramePointerUsed)
+{
+ var_types type = genActualType(varDsc->TypeGet());
+
+ if (varDsc->lvIsInReg())
+ {
+ siFillRegisterVarLoc(varDsc, type, baseReg, offset, isFramePointerUsed);
+ }
+ else
+ {
+ siFillStackVarLoc(varDsc, type, baseReg, offset, isFramePointerUsed);
+ }
+}
+
+//------------------------------------------------------------------------
+// getSiVarLoc: Creates a "CodegenInterface::siVarLoc" instance from using the properties
+// of the "psiScope" instance.
+//
+// Notes:
+// Called for every psiScope in "psiScopeList" codegen.h
+CodeGenInterface::siVarLoc CodeGen::psiScope::getSiVarLoc() const
+{
+ CodeGenInterface::siVarLoc varLoc;
+
+ if (scRegister)
+ {
+ varLoc.vlType = VLT_REG;
+ varLoc.vlReg.vlrReg = (regNumber)u1.scRegNum;
+ }
+ else
+ {
+ varLoc.vlType = VLT_STK;
+ varLoc.vlStk.vlsBaseReg = (regNumber)u2.scBaseReg;
+ varLoc.vlStk.vlsOffset = u2.scOffset;
+ }
+
+ return varLoc;
+}
+
+//------------------------------------------------------------------------
+// getSiVarLoc: Returns a "siVarLoc" instance representing the place where the variable
+// is given its description, "baseReg", and "offset" (if needed).
+//
+// Arguments:
+// varDsc - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
+// scope - a "siScope" Scope info of the variable.
+//
+// Return Value:
+// A "siVarLoc" filled with the correct case struct fields for the variable, which could live
+// in a register, an stack position, or a combination of both.
+//
+// Notes:
+// Called for each siScope in siScopeList when "genSetScopeInfo".
+CodeGenInterface::siVarLoc CodeGen::getSiVarLoc(const LclVarDsc* varDsc, const siScope* scope) const
+{
+ // For stack vars, find the base register, and offset
+
+ regNumber baseReg;
+ signed offset = varDsc->lvStkOffs;
+
+ if (!varDsc->lvFramePointerBased)
+ {
+ baseReg = REG_SPBASE;
+ offset += scope->scStackLevel;
+ }
+ else
+ {
+ baseReg = REG_FPBASE;
+ }
+
+ return CodeGenInterface::siVarLoc(varDsc, baseReg, offset, isFramePointerUsed());
+}
+
+//------------------------------------------------------------------------
+// siFillStackVarLoc: Fill "siVarLoc" struct indicating the stack position of the variable
+// using "LclVarDsc" and "baseReg"/"offset".
+//
+// Arguments:
+// varDsc - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
+// varLoc - a "siVarLoc &" to fill with the data of the "varDsc".
+// type - a "var_types" which indicate the type of the variable.
+// baseReg - a "regNumber" use as a base for the offset.
+// offset - a signed amount of bytes distance from "baseReg" for the position of the variable.
+// isFramePointerUsed - a boolean variable
+//
+// Notes:
+// The "varLoc" argument is filled depending of the "type" argument but as a VLT_STK... variation.
+// "baseReg" and "offset" are used to indicate the position of the variable in the stack.
+void CodeGenInterface::siVarLoc::siFillStackVarLoc(
+ const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed)
+{
+ assert(offset != BAD_STK_OFFS);
+
+ switch (type)
+ {
+ case TYP_INT:
+ case TYP_REF:
+ case TYP_BYREF:
+ case TYP_FLOAT:
+ case TYP_STRUCT:
+ case TYP_BLK: // Needed because of the TYP_BLK stress mode
+#ifdef FEATURE_SIMD
+ case TYP_SIMD8:
+ case TYP_SIMD12:
+ case TYP_SIMD16:
+ case TYP_SIMD32:
+#endif
+#ifdef _TARGET_64BIT_
+ case TYP_LONG:
+ case TYP_DOUBLE:
+#endif // _TARGET_64BIT_
+#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+ // In the AMD64 ABI we are supposed to pass a struct by reference when its
+ // size is not 1, 2, 4 or 8 bytes in size. During fgMorph, the compiler modifies
+ // the IR to comply with the ABI and therefore changes the type of the lclVar
+ // that holds the struct from TYP_STRUCT to TYP_BYREF but it gives us a hint that
+ // this is still a struct by setting the lvIsTemp flag.
+ // The same is true for ARM64 and structs > 16 bytes.
+ // (See Compiler::fgMarkImplicitByRefArgs in Morph.cpp for further detail)
+ // Now, the VM expects a special enum for these type of local vars: VLT_STK_BYREF
+ // to accomodate for this situation.
+ if (varDsc->lvType == TYP_BYREF && varDsc->lvIsTemp)
+ {
+ assert(varDsc->lvIsParam);
+ this->vlType = VLT_STK_BYREF;
+ }
+ else
+#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+ {
+ this->vlType = VLT_STK;
+ }
+ this->vlStk.vlsBaseReg = baseReg;
+ this->vlStk.vlsOffset = offset;
+ if (!isFramePointerUsed && this->vlStk.vlsBaseReg == REG_SPBASE)
+ {
+ this->vlStk.vlsBaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
+ }
+ break;
+
+#ifndef _TARGET_64BIT_
+ case TYP_LONG:
+ case TYP_DOUBLE:
+ this->vlType = VLT_STK2;
+ this->vlStk2.vls2BaseReg = baseReg;
+ this->vlStk2.vls2Offset = offset;
+ if (!isFramePointerUsed && this->vlStk2.vls2BaseReg == REG_SPBASE)
+ {
+ this->vlStk2.vls2BaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
+ }
+ break;
+#endif // !_TARGET_64BIT_
+
+ default:
+ noway_assert(!"Invalid type");
+ }
+}
+
+//------------------------------------------------------------------------
+// siFillRegisterVarLoc: Fill "siVarLoc" struct indicating the register position of the variable
+// using "LclVarDsc" and "baseReg"/"offset" if it has a part in the stack (x64 bit float or long).
+//
+// Arguments:
+// varDsc - a "LclVarDsc *" to the variable it is desired to build the "siVarLoc".
+// varLoc - a "siVarLoc &" to fill with the data of the "varDsc".
+// type - a "var_types" which indicate the type of the variable.
+// baseReg - a "regNumber" use as a base for the offset.
+// offset - a signed amount of bytes distance from "baseReg" for the position of the variable.
+// isFramePointerUsed - a boolean indicating whether the current method sets up an
+// explicit stack frame or not.
+//
+// Notes:
+// The "varLoc" argument is filled depending of the "type" argument but as a VLT_REG... variation.
+// "baseReg" and "offset" are used .for not 64 bit and values that are splitted in two parts.
+void CodeGenInterface::siVarLoc::siFillRegisterVarLoc(
+ const LclVarDsc* varDsc, var_types type, regNumber baseReg, int offset, bool isFramePointerUsed)
+{
+ switch (type)
+ {
+ case TYP_INT:
+ case TYP_REF:
+ case TYP_BYREF:
+#ifdef _TARGET_64BIT_
+ case TYP_LONG:
+#endif // _TARGET_64BIT_
+ this->vlType = VLT_REG;
+ this->vlReg.vlrReg = varDsc->lvRegNum;
+ break;
+
+#ifndef _TARGET_64BIT_
+ case TYP_LONG:
+#if !CPU_HAS_FP_SUPPORT
+ case TYP_DOUBLE:
+#endif
+ if (varDsc->lvOtherReg != REG_STK)
+ {
+ this->vlType = VLT_REG_REG;
+ this->vlRegReg.vlrrReg1 = varDsc->lvRegNum;
+ this->vlRegReg.vlrrReg2 = varDsc->lvOtherReg;
+ }
+ else
+ {
+ this->vlType = VLT_REG_STK;
+ this->vlRegStk.vlrsReg = varDsc->lvRegNum;
+ this->vlRegStk.vlrsStk.vlrssBaseReg = baseReg;
+ if (isFramePointerUsed && this->vlRegStk.vlrsStk.vlrssBaseReg == REG_SPBASE)
+ {
+ this->vlRegStk.vlrsStk.vlrssBaseReg = (regNumber)ICorDebugInfo::REGNUM_AMBIENT_SP;
+ }
+ this->vlRegStk.vlrsStk.vlrssOffset = offset + sizeof(int);
+ }
+ break;
+#endif // !_TARGET_64BIT_
+
+#ifdef _TARGET_64BIT_
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
+ // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15,
+ // so no XMM registers can get debug information.
+ this->vlType = VLT_REG_FP;
+ this->vlReg.vlrReg = varDsc->lvRegNum;
+ break;
+
+#else // !_TARGET_64BIT_
+
+#if CPU_HAS_FP_SUPPORT
+ case TYP_FLOAT:
+ case TYP_DOUBLE:
+ if (isFloatRegType(type))
+ {
+ this->vlType = VLT_FPSTK;
+ this->vlFPstk.vlfReg = varDsc->lvRegNum;
+ }
+ break;
+#endif // CPU_HAS_FP_SUPPORT
+
+#endif // !_TARGET_64BIT_
+
+#ifdef FEATURE_SIMD
+ case TYP_SIMD8:
+ case TYP_SIMD12:
+ case TYP_SIMD16:
+ case TYP_SIMD32:
+ this->vlType = VLT_REG_FP;
+
+ // TODO-AMD64-Bug: ndp\clr\src\inc\corinfo.h has a definition of RegNum that only goes up to R15,
+ // so no XMM registers can get debug information.
+ //
+ // Note: Need to initialize vlrReg field, otherwise during jit dump hitting an assert
+ // in eeDispVar() --> getRegName() that regNumber is valid.
+ this->vlReg.vlrReg = varDsc->lvRegNum;
+ break;
+#endif // FEATURE_SIMD
+
+ default:
+ noway_assert(!"Invalid type");
+ }
+}
+
/*============================================================================
*
* Implementation for ScopeInfo
assert((unsigned)ICorDebugInfo::REGNUM_EDI == REG_EDI);
#endif
- assert((unsigned)ICorDebugInfo::VLT_REG == Compiler::VLT_REG);
- assert((unsigned)ICorDebugInfo::VLT_STK == Compiler::VLT_STK);
- assert((unsigned)ICorDebugInfo::VLT_REG_REG == Compiler::VLT_REG_REG);
- assert((unsigned)ICorDebugInfo::VLT_REG_STK == Compiler::VLT_REG_STK);
- assert((unsigned)ICorDebugInfo::VLT_STK_REG == Compiler::VLT_STK_REG);
- assert((unsigned)ICorDebugInfo::VLT_STK2 == Compiler::VLT_STK2);
- assert((unsigned)ICorDebugInfo::VLT_FPSTK == Compiler::VLT_FPSTK);
- assert((unsigned)ICorDebugInfo::VLT_FIXED_VA == Compiler::VLT_FIXED_VA);
- assert((unsigned)ICorDebugInfo::VLT_COUNT == Compiler::VLT_COUNT);
- assert((unsigned)ICorDebugInfo::VLT_INVALID == Compiler::VLT_INVALID);
+ assert((unsigned)ICorDebugInfo::VLT_REG == CodeGenInterface::VLT_REG);
+ assert((unsigned)ICorDebugInfo::VLT_STK == CodeGenInterface::VLT_STK);
+ assert((unsigned)ICorDebugInfo::VLT_REG_REG == CodeGenInterface::VLT_REG_REG);
+ assert((unsigned)ICorDebugInfo::VLT_REG_STK == CodeGenInterface::VLT_REG_STK);
+ assert((unsigned)ICorDebugInfo::VLT_STK_REG == CodeGenInterface::VLT_STK_REG);
+ assert((unsigned)ICorDebugInfo::VLT_STK2 == CodeGenInterface::VLT_STK2);
+ assert((unsigned)ICorDebugInfo::VLT_FPSTK == CodeGenInterface::VLT_FPSTK);
+ assert((unsigned)ICorDebugInfo::VLT_FIXED_VA == CodeGenInterface::VLT_FIXED_VA);
+ assert((unsigned)ICorDebugInfo::VLT_COUNT == CodeGenInterface::VLT_COUNT);
+ assert((unsigned)ICorDebugInfo::VLT_INVALID == CodeGenInterface::VLT_INVALID);
/* ICorDebugInfo::VarLoc and siVarLoc should overlap exactly as we cast
* one to the other in eeSetLVinfo()
* Below is a "required but not sufficient" condition
*/
- assert(sizeof(ICorDebugInfo::VarLoc) == sizeof(Compiler::siVarLoc));
+ assert(sizeof(ICorDebugInfo::VarLoc) == sizeof(CodeGenInterface::siVarLoc));
assert(compiler->opts.compScopeInfo);