Skip to content

Commit f223627

Browse files
Refactor emitInsSizeSVCalcDisp to more closely match the emitOutputSV checks (#117430)
1 parent f03c775 commit f223627

File tree

1 file changed

+49
-191
lines changed

1 file changed

+49
-191
lines changed

src/coreclr/jit/emitxarch.cpp

Lines changed: 49 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -5109,215 +5109,79 @@ inline UNATIVE_OFFSET emitter::emitInsSizeSVCalcDisp(instrDesc* id, code_t code,
51095109
{
51105110
instruction ins = id->idIns();
51115111
UNATIVE_OFFSET size = emitInsSize(id, code, /* includeRexPrefixSize */ true);
5112-
UNATIVE_OFFSET offs;
5113-
bool offsIsUpperBound = true;
5114-
bool EBPbased = true;
51155112

5116-
/* Is this a temporary? */
5113+
int adr;
5114+
bool EBPbased;
5115+
bool dspInByte;
5116+
bool dspIsZero;
51175117

5118-
if (var < 0)
5119-
{
5120-
/* An address off of ESP takes an extra byte */
5118+
adr = emitComp->lvaFrameAddress(var, &EBPbased);
5119+
dsp = adr + id->idAddr()->iiaLclVar.lvaOffset();
51215120

5122-
if (!emitHasFramePtr)
5123-
{
5124-
size++;
5125-
}
5121+
dspIsZero = (dsp == 0);
51265122

5127-
// The offset is already assigned. Find the temp.
5128-
TempDsc* tmp = codeGen->regSet.tmpFindNum(var, RegSet::TEMP_USAGE_USED);
5129-
if (tmp == nullptr)
5130-
{
5131-
// It might be in the free lists, if we're working on zero initializing the temps.
5132-
tmp = codeGen->regSet.tmpFindNum(var, RegSet::TEMP_USAGE_FREE);
5133-
}
5134-
assert(tmp != nullptr);
5135-
offs = tmp->tdTempOffs();
5123+
bool tryCompress = true;
51365124

5137-
// We only care about the magnitude of the offset here, to determine instruction size.
5138-
if (emitComp->isFramePointerUsed())
5139-
{
5140-
if ((int)offs < 0)
5141-
{
5142-
offs = -(int)offs;
5143-
}
5144-
}
5145-
else
5146-
{
5147-
// SP-based offsets must already be positive.
5148-
assert((int)offs >= 0);
5149-
}
5125+
if (EBPbased)
5126+
{
5127+
// EBP always requires a displacement
5128+
dspIsZero = false;
51505129
}
51515130
else
51525131
{
5153-
5154-
/* Get the frame offset of the (non-temp) variable */
5155-
5156-
offs = dsp + emitComp->lvaFrameAddress(var, &EBPbased);
5157-
5158-
/* An address off of ESP takes an extra byte */
5159-
5160-
if (!EBPbased)
5161-
{
5162-
++size;
5163-
}
5164-
5165-
/* Is this a stack parameter reference? */
5166-
5167-
if ((emitComp->lvaIsParameter(var) && !emitComp->lvaParamHasLocalStackSpace(var)) ||
5168-
(static_cast<unsigned>(var) == emitComp->lvaRetAddrVar))
5169-
{
5170-
/* If no EBP frame, arguments and ret addr are off of ESP, above temps */
5171-
5172-
if (!EBPbased)
5173-
{
5174-
assert((int)offs >= 0);
5175-
}
5176-
}
5177-
else
5178-
{
5179-
/* Locals off of EBP are at negative offsets */
5180-
5181-
if (EBPbased)
5182-
{
5183-
#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)
5184-
// If localloc is not used, then ebp chaining is done and hence
5185-
// offset of locals will be at negative offsets, Otherwise offsets
5186-
// will be positive. In future, when RBP gets positioned in the
5187-
// middle of the frame so as to optimize instruction encoding size,
5188-
// the below asserts needs to be modified appropriately.
5189-
// However, for Unix platforms, we always do frame pointer chaining,
5190-
// so offsets from the frame pointer will always be negative.
5191-
if (emitComp->compLocallocUsed || emitComp->opts.compDbgEnC)
5192-
{
5193-
noway_assert((int)offs >= 0);
5194-
}
5195-
else
5196-
#endif
5197-
{
5198-
// Dev10 804810 - failing this assert can lead to bad codegen and runtime crashes
5199-
5200-
#ifdef UNIX_AMD64_ABI
5201-
const LclVarDsc* varDsc = emitComp->lvaGetDesc(var);
5202-
bool isRegPassedArg = varDsc->lvIsParam && varDsc->lvIsRegArg;
5203-
// Register passed args could have a stack offset of 0.
5204-
noway_assert((int)offs < 0 || isRegPassedArg || emitComp->opts.IsOSR());
5205-
#else // !UNIX_AMD64_ABI
5206-
5207-
// OSR transitioning to RBP frame currently can have mid-frame FP
5208-
noway_assert(((int)offs < 0) || emitComp->opts.IsOSR());
5209-
#endif // !UNIX_AMD64_ABI
5210-
}
5211-
5212-
assert(emitComp->lvaTempsHaveLargerOffsetThanVars());
5213-
5214-
if (IsEvexEncodableInstruction(ins) || IsApxExtendedEvexInstruction(ins))
5215-
{
5216-
ssize_t compressedDsp;
5217-
bool fitsInByte;
5218-
5219-
if (TryEvexCompressDisp8Byte(id, int(offs), &compressedDsp, &fitsInByte))
5220-
{
5221-
if (!TakesEvexPrefix(id))
5222-
{
5223-
// We mispredicted the adjusted size since we didn't know we'd use the EVEX
5224-
// encoding due to comprssed displacement. So we need an additional adjustment
5225-
size += emitGetEvexPrefixSize(id) - emitGetVexPrefixSize(id);
5226-
}
5227-
SetEvexCompressedDisplacement(id);
5228-
}
5229-
5230-
return size + (fitsInByte ? sizeof(char) : sizeof(int));
5231-
}
5232-
else if ((int)offs < 0)
5233-
{
5234-
// offset is negative
5235-
return size + ((int(offs) >= SCHAR_MIN) ? sizeof(char) : sizeof(int));
5236-
}
5237-
#ifdef TARGET_AMD64
5238-
else
5239-
{
5240-
// This case arises for localloc frames
5241-
return size + ((offs <= SCHAR_MAX) ? sizeof(char) : sizeof(int));
5242-
}
5243-
#endif // TARGET_AMD64
5244-
}
5245-
}
5246-
}
5247-
5248-
assert((int)offs >= 0);
5132+
// An address off of ESP takes an extra byte
5133+
size++;
52495134

52505135
#if !FEATURE_FIXED_OUT_ARGS
5136+
// Adjust the offset by the amount currently pushed on the CPU stack
5137+
dsp += emitCurStackLvl;
52515138

5252-
/* Are we addressing off of ESP? */
5253-
5254-
if (!emitHasFramePtr)
5255-
{
5256-
/* Adjust the effective offset if necessary */
5257-
5258-
if (emitCntStackDepth)
5259-
offs += emitCurStackLvl;
5260-
5261-
// we could (and used to) check for the special case [sp] here but the stack offset
5262-
// estimator was off, and there is very little harm in overestimating for such a
5263-
// rare case.
5264-
}
5265-
5139+
// At this point, the amount pushed onto the stack is an estimate and
5140+
// so we cannot reliably predict if it will be zero or if compression
5141+
// can occur. So we'll pessimize to not compressing and not using zero
5142+
// displacement here, potentially resulting in over-allocation of bytes
5143+
tryCompress = false;
5144+
dspIsZero = false;
52665145
#endif // !FEATURE_FIXED_OUT_ARGS
5267-
5268-
bool useSmallEncoding = false;
5146+
}
52695147

52705148
if (IsEvexEncodableInstruction(ins) || IsApxExtendedEvexInstruction(ins))
52715149
{
5272-
ssize_t compressedDsp;
5273-
5274-
#if !FEATURE_FIXED_OUT_ARGS
5275-
if (!emitHasFramePtr)
5150+
if (tryCompress)
52765151
{
5277-
// We cannot use compressed displacement because the stack offset estimator
5278-
// can be off and the compression is only usable in very precise scenarios
5279-
//
5280-
// But we can still predict small encoding for VEX encodable instructions
5152+
ssize_t compressedDsp;
52815153

5282-
if (!TakesEvexPrefix(id))
5154+
if (TryEvexCompressDisp8Byte(id, dsp, &compressedDsp, &dspInByte))
52835155
{
5284-
#ifdef TARGET_AMD64
5285-
useSmallEncoding = (SCHAR_MIN <= (int)offs) && ((int)offs <= SCHAR_MAX);
5286-
#else
5287-
useSmallEncoding = (offs <= size_t(SCHAR_MAX));
5288-
#endif
5156+
SetEvexCompressedDisplacement(id);
52895157
}
52905158
}
5159+
else if (TakesEvexPrefix(id))
5160+
{
5161+
// EVEX requires compressed displacement to fit in a byte
5162+
dspInByte = false;
5163+
}
52915164
else
5292-
#endif // FEATURE_FIXED_OUT_ARGS
5293-
if (TryEvexCompressDisp8Byte(id, int(offs), &compressedDsp, &useSmallEncoding))
5294-
{
5295-
if (!TakesEvexPrefix(id))
5296-
{
5297-
// We mispredicted the adjusted size since we didn't know we'd use the EVEX
5298-
// encoding due to compressed displacement. So we need an additional adjustment
5299-
size += emitGetEvexPrefixSize(id) - emitGetVexPrefixSize(id);
5300-
}
5301-
SetEvexCompressedDisplacement(id);
5302-
}
5165+
{
5166+
dspInByte = ((signed char)dsp == (ssize_t)dsp);
5167+
}
53035168
}
53045169
else
53055170
{
5306-
#ifdef TARGET_AMD64
5307-
useSmallEncoding = (SCHAR_MIN <= (int)offs) && ((int)offs <= SCHAR_MAX);
5308-
#else
5309-
useSmallEncoding = (offs <= size_t(SCHAR_MAX));
5310-
#endif
5171+
dspInByte = ((signed char)dsp == (ssize_t)dsp);
53115172
}
53125173

5313-
// If it is ESP based, and the offset is zero, we will not encode the disp part.
5314-
if (!EBPbased && (offs == 0))
5174+
if (dspIsZero)
53155175
{
53165176
return size;
53175177
}
5178+
else if (dspInByte)
5179+
{
5180+
return size + sizeof(char);
5181+
}
53185182
else
53195183
{
5320-
return size + (useSmallEncoding ? sizeof(char) : sizeof(int));
5184+
return size + sizeof(int);
53215185
}
53225186
}
53235187

@@ -5326,24 +5190,24 @@ inline UNATIVE_OFFSET emitter::emitInsSizeSV(instrDesc* id, code_t code, int var
53265190
assert(id->idIns() != INS_invalid);
53275191
instruction ins = id->idIns();
53285192
emitAttr attrSize = id->idOpSize();
5329-
UNATIVE_OFFSET prefix = emitGetAdjustedSize(id, code);
5193+
UNATIVE_OFFSET size = emitInsSizeSVCalcDisp(id, code, var, dsp);
5194+
5195+
size += emitGetAdjustedSize(id, code);
53305196

53315197
// REX prefix
53325198
if (TakesRexWPrefix(id) || IsExtendedReg(id->idReg1(), attrSize) || IsExtendedReg(id->idReg2(), attrSize))
53335199
{
5334-
prefix += emitGetRexPrefixSize(id, ins);
5200+
size += emitGetRexPrefixSize(id, ins);
53355201
}
53365202

5337-
return prefix + emitInsSizeSVCalcDisp(id, code, var, dsp);
5203+
return size;
53385204
}
53395205

53405206
inline UNATIVE_OFFSET emitter::emitInsSizeSV(instrDesc* id, code_t code, int var, int dsp, int val)
53415207
{
53425208
assert(id->idIns() != INS_invalid);
53435209
instruction ins = id->idIns();
5344-
emitAttr attrSize = id->idOpSize();
5345-
UNATIVE_OFFSET valSize = EA_SIZE_IN_BYTES(attrSize);
5346-
UNATIVE_OFFSET prefix = emitGetAdjustedSize(id, code);
5210+
UNATIVE_OFFSET valSize = EA_SIZE_IN_BYTES(id->idOpSize());
53475211
bool valInByte = ((signed char)val == val) && (ins != INS_mov) && (ins != INS_test);
53485212

53495213
#ifdef TARGET_AMD64
@@ -5372,13 +5236,7 @@ inline UNATIVE_OFFSET emitter::emitInsSizeSV(instrDesc* id, code_t code, int var
53725236
assert(!IsSSEOrAVXInstruction(ins));
53735237
}
53745238

5375-
// 64-bit operand instructions will need a REX.W prefix
5376-
if (TakesRexWPrefix(id) || IsExtendedReg(id->idReg1(), attrSize) || IsExtendedReg(id->idReg2(), attrSize))
5377-
{
5378-
prefix += emitGetRexPrefixSize(id, ins);
5379-
}
5380-
5381-
return prefix + valSize + emitInsSizeSVCalcDisp(id, code, var, dsp);
5239+
return valSize + emitInsSizeSV(id, code, var, dsp);
53825240
}
53835241

53845242
/*****************************************************************************/

0 commit comments

Comments
 (0)