summaryrefslogtreecommitdiff
path: root/src/jit/compiler.hpp
diff options
context:
space:
mode:
authorBruce Forstall <Bruce_Forstall@msn.com>2018-12-05 23:48:11 -0800
committerBruce Forstall <Bruce_Forstall@msn.com>2018-12-05 23:48:11 -0800
commitc153d9fc6627e5bb35e31eea6038f64f2a006022 (patch)
tree1cd3d5b8d10af4d71c7766e0e4c4d7cf7ff9ec5a /src/jit/compiler.hpp
parent8aa0869eb9153429091fdba49469d89ec33092cb (diff)
downloadcoreclr-c153d9fc6627e5bb35e31eea6038f64f2a006022.tar.gz
coreclr-c153d9fc6627e5bb35e31eea6038f64f2a006022.tar.bz2
coreclr-c153d9fc6627e5bb35e31eea6038f64f2a006022.zip
Fix arm32 local variable references
Arm32 has different addressing mode offset ranges for floating-point and integer instructions. In addition, the ranges aren't too large. So in functions with a frame pointer, we try to access some variables using the frame pointer and some with the stack pointer, to expand the total number of variables we can access without allocating a "reserved register" just used for constructing large offsets. This calculation was incorrect for struct variables that contained floats, as float fields require calculating using the floating point range, but we were calculating using the variable type (struct), instead of the instruction type (floating-point). In addition, we were not correctly calculating the frame pointer range using the actual variable offset plus "within variable" offset (struct member offset). Added a test that covers some of these cases. Fixes #19537
Diffstat (limited to 'src/jit/compiler.hpp')
-rw-r--r--src/jit/compiler.hpp83
1 files changed, 46 insertions, 37 deletions
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index e798741ea4..47c4ef1e4d 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -2064,25 +2064,37 @@ inline int Compiler::lvaCachedGenericContextArgOffset()
return lvaCachedGenericContextArgOffs;
}
-/*****************************************************************************
- *
- * Return the stack framed offset of the given variable; set *FPbased to
- * true if the variable is addressed off of FP, false if it's addressed
- * off of SP. Note that 'varNum' can be a negated spill-temporary var index.
- *
- * mustBeFPBased - strong about whether the base reg is FP. But it is also
- * strong about not being FPBased after FINAL_FRAME_LAYOUT. i.e.,
- * it enforces SP based.
- *
- * addrModeOffset - is the addressing mode offset, for example: v02 + 0x10
- * So, V02 itself is at offset sp + 0x10 and then addrModeOffset is what gets
- * added beyond that.
- */
-
+//------------------------------------------------------------------------
+// lvaFrameAddress: Determine the stack frame offset of the given variable,
+// and how to generate an address to that stack frame.
+//
+// Arguments:
+// varNum - The variable to inquire about. Positive for user variables
+// or arguments, negative for spill-temporaries.
+// mustBeFPBased - [_TARGET_ARM_ only] True if the base register must be FP.
+// After FINAL_FRAME_LAYOUT, if false, it also requires SP base register.
+// pBaseReg - [_TARGET_ARM_ only] Out arg. *pBaseReg is set to the base
+// register to use.
+// addrModeOffset - [_TARGET_ARM_ only] The mode offset within the variable that we need to address.
+// For example, for a large struct local, and a struct field reference, this will be the offset
+// of the field. Thus, for V02 + 0x28, if V02 itself is at offset SP + 0x10
+// then addrModeOffset is what gets added beyond that, here 0x28.
+// isFloatUsage - [_TARGET_ARM_ only] True if the instruction being generated is a floating
+// point instruction. This requires using floating-point offset restrictions.
+// Note that a variable can be non-float, e.g., struct, but accessed as a
+// float local field.
+// pFPbased - [non-_TARGET_ARM_] Out arg. Set *FPbased to true if the
+// variable is addressed off of FP, false if it's addressed
+// off of SP.
+//
+// Return Value:
+// Returns the variable offset from the given base register.
+//
inline
#ifdef _TARGET_ARM_
int
- Compiler::lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset)
+ Compiler::lvaFrameAddress(
+ int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage)
#else
int
Compiler::lvaFrameAddress(int varNum, bool* pFPbased)
@@ -2090,17 +2102,15 @@ inline
{
assert(lvaDoneFrameLayout != NO_FRAME_LAYOUT);
- int offset;
- bool FPbased;
- bool fConservative = false;
- var_types type = TYP_UNDEF;
+ int varOffset;
+ bool FPbased;
+ bool fConservative = false;
if (varNum >= 0)
{
LclVarDsc* varDsc;
assert((unsigned)varNum < lvaCount);
varDsc = lvaTable + varNum;
- type = varDsc->TypeGet();
bool isPrespilledArg = false;
#if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
isPrespilledArg = varDsc->lvIsParam && compIsProfilerHookNeeded() &&
@@ -2144,7 +2154,7 @@ inline
}
#endif // DEBUG
- offset = varDsc->lvStkOffs;
+ varOffset = varDsc->lvStkOffs;
}
else // Its a spill-temp
{
@@ -2158,8 +2168,7 @@ inline
tmpDsc = codeGen->regSet.tmpFindNum(varNum, RegSet::TEMP_USAGE_USED);
}
assert(tmpDsc != nullptr);
- offset = tmpDsc->tdTempOffs();
- type = tmpDsc->tdTempType();
+ varOffset = tmpDsc->tdTempOffs();
}
else
{
@@ -2186,7 +2195,6 @@ inline
// : :
// ---------------------------------------------------
- type = compFloatingPointUsed ? TYP_FLOAT : TYP_INT;
fConservative = true;
if (!FPbased)
{
@@ -2197,7 +2205,7 @@ inline
#else
int outGoingArgSpaceSize = 0;
#endif
- offset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
+ varOffset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
}
else
{
@@ -2205,9 +2213,9 @@ inline
CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef _TARGET_ARM_
- offset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
+ varOffset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
#else
- offset = -(codeGen->genTotalFrameSize());
+ varOffset = -(codeGen->genTotalFrameSize());
#endif
}
}
@@ -2229,19 +2237,20 @@ inline
// we have already selected the instruction. MinOpts will always reserve R10, so
// for MinOpts always use SP-based offsets, using R10 as necessary, for simplicity.
- int spOffset = fConservative ? compLclFrameSize : offset + codeGen->genSPtoFPdelta();
- int actualOffset = spOffset + addrModeOffset;
- int encodingLimitUpper = varTypeIsFloating(type) ? 0x3FC : 0xFFF;
- int encodingLimitLower = varTypeIsFloating(type) ? -0x3FC : -0xFF;
+ int spVarOffset = fConservative ? compLclFrameSize : varOffset + codeGen->genSPtoFPdelta();
+ int actualSPOffset = spVarOffset + addrModeOffset;
+ int actualFPOffset = varOffset + addrModeOffset;
+ int encodingLimitUpper = isFloatUsage ? 0x3FC : 0xFFF;
+ int encodingLimitLower = isFloatUsage ? -0x3FC : -0xFF;
// Use SP-based encoding. During encoding, we'll pick the best encoding for the actual offset we have.
- if (opts.MinOpts() || (actualOffset <= encodingLimitUpper))
+ if (opts.MinOpts() || (actualSPOffset <= encodingLimitUpper))
{
- offset = spOffset;
+ varOffset = spVarOffset;
*pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
}
// Use Frame Pointer (R11)-based encoding.
- else if ((encodingLimitLower <= offset) && (offset <= encodingLimitUpper))
+ else if ((encodingLimitLower <= actualFPOffset) && (actualFPOffset <= encodingLimitUpper))
{
*pBaseReg = REG_FPBASE;
}
@@ -2250,7 +2259,7 @@ inline
// the "reserved register", which will get used during encoding.
else
{
- offset = spOffset;
+ varOffset = spVarOffset;
*pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
}
}
@@ -2263,7 +2272,7 @@ inline
*pFPbased = FPbased;
#endif
- return offset;
+ return varOffset;
}
inline bool Compiler::lvaIsParameter(unsigned varNum)