Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit a8d5756

Browse files
authored
Fix Arm64 UpperVector save/restore (#24043)
* Fix Arm64 UpperVector save/restore Change the general handling of end-of-block restores so that we always have a RefPosition on which to allocate the register needed on Arm64. Fix #23885
1 parent a36bc61 commit a8d5756

File tree

7 files changed

+345
-102
lines changed

7 files changed

+345
-102
lines changed

src/jit/codegenarm64.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4911,9 +4911,8 @@ void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)
49114911
// When a 16-byte SIMD value is live across a call, the register allocator will use this intrinsic
49124912
// to cause the upper half to be saved. It will first attempt to find another, unused, callee-save
49134913
// register. If such a register cannot be found, it will save it to an available caller-save register.
4914-
// In that case, this node will be marked GTF_SPILL, which will cause genProduceReg to save the 8 byte
4915-
// value to the stack. (Note that if there are no caller-save registers available, the entire 16 byte
4916-
// value will be spilled to the stack.)
4914+
// In that case, this node will be marked GTF_SPILL, which will cause this method to save
4915+
// the upper half to the lclVar's home location.
49174916
//
49184917
void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
49194918
{
@@ -4928,7 +4927,23 @@ void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
49284927
assert(targetReg != REG_NA);
49294928
getEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, targetReg, op1Reg, 0, 1);
49304929

4931-
genProduceReg(simdNode);
4930+
if ((simdNode->gtFlags & GTF_SPILL) != 0)
4931+
{
4932+
// This is not a normal spill; we'll spill it to the lclVar location.
4933+
// The localVar must have a stack home.
4934+
unsigned varNum = op1->AsLclVarCommon()->gtLclNum;
4935+
LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);
4936+
assert(varDsc->lvOnFrame);
4937+
// We want to store this to the upper 8 bytes of this localVar's home.
4938+
int offset = 8;
4939+
4940+
emitAttr attr = emitTypeSize(TYP_SIMD8);
4941+
getEmitter()->emitIns_S_R(INS_str, attr, targetReg, varNum, offset);
4942+
}
4943+
else
4944+
{
4945+
genProduceReg(simdNode);
4946+
}
49324947
}
49334948

49344949
//-----------------------------------------------------------------------------
@@ -4946,11 +4961,7 @@ void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
49464961
// have their home register, this node has its targetReg on the lclVar child, and its source
49474962
// on the simdNode.
49484963
// Regarding spill, please see the note above on genSIMDIntrinsicUpperSave. If we have spilled
4949-
// an upper-half to a caller save register, this node will be marked GTF_SPILLED. However, unlike
4950-
// most spill scenarios, the saved tree will be different from the restored tree, but the spill
4951-
// restore logic, which is triggered by the call to genConsumeReg, requires us to provide the
4952-
// spilled tree (saveNode) in order to perform the reload. We can easily find that tree,
4953-
// as it is in the spill descriptor for the register from which it was saved.
4964+
// an upper-half to the lclVar's home location, this node will be marked GTF_SPILLED.
49544965
//
49554966
void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode)
49564967
{
@@ -4966,9 +4977,14 @@ void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode)
49664977
assert(srcReg != REG_NA);
49674978
if (simdNode->gtFlags & GTF_SPILLED)
49684979
{
4969-
GenTree* saveNode = regSet.rsSpillDesc[srcReg]->spillTree;
4970-
noway_assert(saveNode != nullptr && (saveNode->gtRegNum == srcReg));
4971-
genConsumeReg(saveNode);
4980+
// The localVar must have a stack home.
4981+
LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);
4982+
assert(varDsc->lvOnFrame);
4983+
// We will load this from the upper 8 bytes of this localVar's home.
4984+
int offset = 8;
4985+
4986+
emitAttr attr = emitTypeSize(TYP_SIMD8);
4987+
getEmitter()->emitIns_R_S(INS_ldr, attr, srcReg, varNum, offset);
49724988
}
49734989
getEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, lclVarReg, srcReg, 1, 0);
49744990
}

0 commit comments

Comments
 (0)