Skip to content

Commit 90b8ddd

Browse files
author
Sergey Andreenko
authored
Enable StructEnreg by default on all platforms. (#55558)
* enable for arm32. fix arm32 Fix arm/arm64. now we can have contained lclRead for other platforms, not only xarch. * enable x64 unix. * Fix and enable arm64. * fix bad merge and arm32 failures.
1 parent 0663b30 commit 90b8ddd

File tree

13 files changed

+166
-151
lines changed

13 files changed

+166
-151
lines changed

src/coreclr/jit/codegen.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -866,10 +866,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
866866
// Generate code for a GT_BITCAST that is not contained.
867867
void genCodeForBitCast(GenTreeOp* treeNode);
868868

869-
#if defined(TARGET_XARCH)
870869
// Generate the instruction to move a value between register files
871870
void genBitCast(var_types targetType, regNumber targetReg, var_types srcType, regNumber srcReg);
872-
#endif // TARGET_XARCH
873871

874872
struct GenIntCastDesc
875873
{

src/coreclr/jit/codegenarm.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,15 +1044,21 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree)
10441044
//
10451045
void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
10461046
{
1047-
GenTree* data = tree->gtOp1;
1048-
1047+
GenTree* data = tree->gtOp1;
1048+
GenTree* actualData = data->gtSkipReloadOrCopy();
1049+
unsigned regCount = 1;
10491050
// var = call, where call returns a multi-reg return value
10501051
// case is handled separately.
1051-
if (data->gtSkipReloadOrCopy()->IsMultiRegNode())
1052+
if (actualData->IsMultiRegNode())
10521053
{
1053-
genMultiRegStoreToLocal(tree);
1054+
regCount = actualData->IsMultiRegLclVar() ? actualData->AsLclVar()->GetFieldCount(compiler)
1055+
: actualData->GetMultiRegCount();
1056+
if (regCount > 1)
1057+
{
1058+
genMultiRegStoreToLocal(tree);
1059+
}
10541060
}
1055-
else
1061+
if (regCount == 1)
10561062
{
10571063
unsigned varNum = tree->GetLclNum();
10581064
assert(varNum < compiler->lvaCount);

src/coreclr/jit/codegenarm64.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4378,9 +4378,11 @@ void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
43784378
{
43794379
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperSave);
43804380

4381-
GenTree* op1 = simdNode->gtGetOp1();
4382-
assert(op1->IsLocal());
4383-
assert(emitTypeSize(op1->TypeGet()) == 16);
4381+
GenTree* op1 = simdNode->gtGetOp1();
4382+
GenTreeLclVar* lclNode = op1->AsLclVar();
4383+
LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode);
4384+
assert(emitTypeSize(varDsc->GetRegisterType(lclNode)) == 16);
4385+
43844386
regNumber targetReg = simdNode->GetRegNum();
43854387
regNumber op1Reg = genConsumeReg(op1);
43864388
assert(op1Reg != REG_NA);
@@ -4391,8 +4393,7 @@ void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
43914393
{
43924394
// This is not a normal spill; we'll spill it to the lclVar location.
43934395
// The localVar must have a stack home.
4394-
unsigned varNum = op1->AsLclVarCommon()->GetLclNum();
4395-
LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);
4396+
unsigned varNum = lclNode->GetLclNum();
43964397
assert(varDsc->lvOnFrame);
43974398
// We want to store this to the upper 8 bytes of this localVar's home.
43984399
int offset = 8;
@@ -4429,16 +4430,18 @@ void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode)
44294430

44304431
GenTree* op1 = simdNode->gtGetOp1();
44314432
assert(op1->IsLocal());
4432-
assert(emitTypeSize(op1->TypeGet()) == 16);
4433+
GenTreeLclVar* lclNode = op1->AsLclVar();
4434+
LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode);
4435+
assert(emitTypeSize(varDsc->GetRegisterType(lclNode)) == 16);
4436+
44334437
regNumber srcReg = simdNode->GetRegNum();
4434-
regNumber lclVarReg = genConsumeReg(op1);
4435-
unsigned varNum = op1->AsLclVarCommon()->GetLclNum();
4438+
regNumber lclVarReg = genConsumeReg(lclNode);
4439+
unsigned varNum = lclNode->GetLclNum();
44364440
assert(lclVarReg != REG_NA);
44374441
assert(srcReg != REG_NA);
44384442
if (simdNode->gtFlags & GTF_SPILLED)
44394443
{
44404444
// The localVar must have a stack home.
4441-
LclVarDsc* varDsc = compiler->lvaGetDesc(varNum);
44424445
assert(varDsc->lvOnFrame);
44434446
// We will load this from the upper 8 bytes of this localVar's home.
44444447
int offset = 8;

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,58 +1125,6 @@ void CodeGen::genPutArgReg(GenTreeOp* tree)
11251125
genProduceReg(tree);
11261126
}
11271127

1128-
//----------------------------------------------------------------------
1129-
// genCodeForBitCast - Generate code for a GT_BITCAST that is not contained
1130-
//
1131-
// Arguments
1132-
// treeNode - the GT_BITCAST for which we're generating code
1133-
//
1134-
void CodeGen::genCodeForBitCast(GenTreeOp* treeNode)
1135-
{
1136-
regNumber targetReg = treeNode->GetRegNum();
1137-
var_types targetType = treeNode->TypeGet();
1138-
GenTree* op1 = treeNode->gtGetOp1();
1139-
genConsumeRegs(op1);
1140-
if (op1->isContained())
1141-
{
1142-
assert(op1->IsLocal() || op1->isIndir());
1143-
op1->gtType = treeNode->TypeGet();
1144-
op1->SetRegNum(targetReg);
1145-
op1->ClearContained();
1146-
JITDUMP("Changing type of BITCAST source to load directly.");
1147-
genCodeForTreeNode(op1);
1148-
}
1149-
else if (varTypeUsesFloatReg(treeNode) != varTypeUsesFloatReg(op1))
1150-
{
1151-
regNumber srcReg = op1->GetRegNum();
1152-
assert(genTypeSize(op1->TypeGet()) == genTypeSize(targetType));
1153-
#ifdef TARGET_ARM
1154-
if (genTypeSize(targetType) == 8)
1155-
{
1156-
// Converting between long and double on ARM is a special case.
1157-
if (targetType == TYP_LONG)
1158-
{
1159-
regNumber otherReg = treeNode->AsMultiRegOp()->gtOtherReg;
1160-
assert(otherReg != REG_NA);
1161-
inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, srcReg, EA_8BYTE);
1162-
}
1163-
else
1164-
{
1165-
NYI_ARM("Converting from long to double");
1166-
}
1167-
}
1168-
else
1169-
#endif // TARGET_ARM
1170-
{
1171-
inst_Mov(targetType, targetReg, srcReg, /* canSkip */ false);
1172-
}
1173-
}
1174-
else
1175-
{
1176-
inst_Mov(targetType, targetReg, genConsumeReg(op1), /* canSkip */ false);
1177-
}
1178-
}
1179-
11801128
#if FEATURE_ARG_SPLIT
11811129
//---------------------------------------------------------------------
11821130
// genPutArgSplit - generate code for a GT_PUTARG_SPLIT node

src/coreclr/jit/codegencommon.cpp

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3783,7 +3783,8 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
37833783

37843784
varNum = regArgTab[argNum].varNum;
37853785
noway_assert(varNum < compiler->lvaCount);
3786-
varDsc = compiler->lvaTable + varNum;
3786+
varDsc = compiler->lvaTable + varNum;
3787+
const var_types varRegType = varDsc->GetRegisterType();
37873788
noway_assert(varDsc->lvIsParam && varDsc->lvIsRegArg);
37883789

37893790
/* cannot possibly have stack arguments */
@@ -3827,7 +3828,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
38273828
assert(argNum > 0);
38283829
assert(regArgTab[argNum - 1].slot == 1);
38293830
assert(regArgTab[argNum - 1].varNum == varNum);
3830-
assert((varDsc->lvType == TYP_SIMD12) || (varDsc->lvType == TYP_SIMD16));
3831+
assert((varRegType == TYP_SIMD12) || (varRegType == TYP_SIMD16));
38313832
regArgMaskLive &= ~genRegMask(regNum);
38323833
regArgTab[argNum].circular = false;
38333834
change = true;
@@ -4338,9 +4339,10 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
43384339

43394340
varNum = regArgTab[argNum].varNum;
43404341
noway_assert(varNum < compiler->lvaCount);
4341-
varDsc = compiler->lvaTable + varNum;
4342-
var_types regType = regArgTab[argNum].getRegType(compiler);
4343-
regNumber regNum = genMapRegArgNumToRegNum(argNum, regType);
4342+
varDsc = compiler->lvaTable + varNum;
4343+
const var_types regType = regArgTab[argNum].getRegType(compiler);
4344+
const regNumber regNum = genMapRegArgNumToRegNum(argNum, regType);
4345+
const var_types varRegType = varDsc->GetRegisterType();
43444346

43454347
#if defined(UNIX_AMD64_ABI)
43464348
if (regType == TYP_UNDEF)
@@ -4439,7 +4441,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
44394441
assert(regArgTab[argNum].slot == 2);
44404442
assert(argNum > 0);
44414443
assert(regArgTab[argNum - 1].slot == 1);
4442-
assert((varDsc->lvType == TYP_SIMD12) || (varDsc->lvType == TYP_SIMD16));
4444+
assert((varRegType == TYP_SIMD12) || (varRegType == TYP_SIMD16));
44434445
destRegNum = varDsc->GetRegNum();
44444446
noway_assert(regNum != destRegNum);
44454447
continue;
@@ -4509,7 +4511,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere
45094511
noway_assert(regArgTab[nextArgNum].varNum == varNum);
45104512
// Emit a shufpd with a 0 immediate, which preserves the 0th element of the dest reg
45114513
// and moves the 0th element of the src reg into the 1st element of the dest reg.
4512-
GetEmitter()->emitIns_R_R_I(INS_shufpd, emitActualTypeSize(varDsc->lvType), destRegNum, nextRegNum, 0);
4514+
GetEmitter()->emitIns_R_R_I(INS_shufpd, emitActualTypeSize(varRegType), destRegNum, nextRegNum, 0);
45134515
// Set destRegNum to regNum so that we skip the setting of the register below,
45144516
// but mark argNum as processed and clear regNum from the live mask.
45154517
destRegNum = regNum;
@@ -11245,11 +11247,15 @@ void CodeGen::genStructReturn(GenTree* treeNode)
1124511247
assert(regCount <= MAX_RET_REG_COUNT);
1124611248

1124711249
#if FEATURE_MULTIREG_RET
11250+
// Right now the only enregisterable structs supported are SIMD vector types.
1124811251
if (genIsRegCandidateLocal(actualOp1))
1124911252
{
11250-
// Right now the only enregisterable structs supported are SIMD vector types.
11251-
assert(varTypeIsSIMD(op1));
11252-
assert(!actualOp1->AsLclVar()->IsMultiReg());
11253+
#if defined(DEBUG)
11254+
const GenTreeLclVar* lclVar = actualOp1->AsLclVar();
11255+
const LclVarDsc* varDsc = compiler->lvaGetDesc(lclVar);
11256+
assert(varTypeIsSIMD(varDsc->GetRegisterType()));
11257+
assert(!lclVar->IsMultiReg());
11258+
#endif // DEBUG
1125311259
#ifdef FEATURE_SIMD
1125411260
genSIMDSplitReturn(op1, &retTypeDesc);
1125511261
#endif // FEATURE_SIMD
@@ -11329,6 +11335,7 @@ void CodeGen::genMultiRegStoreToLocal(GenTreeLclVar* lclNode)
1132911335
assert(op1->IsMultiRegNode());
1133011336
unsigned regCount =
1133111337
actualOp1->IsMultiRegLclVar() ? actualOp1->AsLclVar()->GetFieldCount(compiler) : actualOp1->GetMultiRegCount();
11338+
assert(regCount > 1);
1133211339

1133311340
// Assumption: current implementation requires that a multi-reg
1133411341
// var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from
@@ -12580,3 +12587,61 @@ void CodeGen::genPoisonFrame(regMaskTP regLiveIn)
1258012587
}
1258112588
}
1258212589
}
12590+
12591+
//----------------------------------------------------------------------
12592+
// genBitCast - Generate the instruction to move a value between register files
12593+
//
12594+
// Arguments
12595+
// targetType - the destination type
12596+
// targetReg - the destination register
12597+
// srcType - the source type
12598+
// srcReg - the source register
12599+
//
12600+
void CodeGen::genBitCast(var_types targetType, regNumber targetReg, var_types srcType, regNumber srcReg)
12601+
{
12602+
const bool srcFltReg = varTypeUsesFloatReg(srcType) || varTypeIsSIMD(srcType);
12603+
assert(srcFltReg == genIsValidFloatReg(srcReg));
12604+
12605+
const bool dstFltReg = varTypeUsesFloatReg(targetType) || varTypeIsSIMD(targetType);
12606+
assert(dstFltReg == genIsValidFloatReg(targetReg));
12607+
12608+
inst_Mov(targetType, targetReg, srcReg, /* canSkip */ true);
12609+
}
12610+
12611+
//----------------------------------------------------------------------
12612+
// genCodeForBitCast - Generate code for a GT_BITCAST that is not contained
12613+
//
12614+
// Arguments
12615+
// treeNode - the GT_BITCAST for which we're generating code
12616+
//
12617+
void CodeGen::genCodeForBitCast(GenTreeOp* treeNode)
12618+
{
12619+
regNumber targetReg = treeNode->GetRegNum();
12620+
var_types targetType = treeNode->TypeGet();
12621+
GenTree* op1 = treeNode->gtGetOp1();
12622+
genConsumeRegs(op1);
12623+
12624+
if (op1->isContained())
12625+
{
12626+
assert(op1->IsLocal() || op1->isIndir());
12627+
if (genIsRegCandidateLocal(op1))
12628+
{
12629+
unsigned lclNum = op1->AsLclVar()->GetLclNum();
12630+
GetEmitter()->emitIns_R_S(ins_Load(treeNode->TypeGet(), compiler->isSIMDTypeLocalAligned(lclNum)),
12631+
emitTypeSize(treeNode), targetReg, lclNum, 0);
12632+
}
12633+
else
12634+
{
12635+
op1->gtType = treeNode->TypeGet();
12636+
op1->SetRegNum(targetReg);
12637+
op1->ClearContained();
12638+
JITDUMP("Changing type of BITCAST source to load directly.\n");
12639+
genCodeForTreeNode(op1);
12640+
}
12641+
}
12642+
else
12643+
{
12644+
genBitCast(targetType, targetReg, op1->TypeGet(), op1->GetRegNum());
12645+
}
12646+
genProduceReg(treeNode);
12647+
}

src/coreclr/jit/codegenlinear.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,6 @@ void CodeGen::genConsumeRegs(GenTree* tree)
15771577
{
15781578
genConsumeAddress(tree);
15791579
}
1580-
#ifdef TARGET_XARCH
15811580
else if (tree->OperIsLocalRead())
15821581
{
15831582
// A contained lcl var must be living on stack and marked as reg optional, or not be a
@@ -1591,6 +1590,7 @@ void CodeGen::genConsumeRegs(GenTree* tree)
15911590
// Update the life of the lcl var.
15921591
genUpdateLife(tree);
15931592
}
1593+
#ifdef TARGET_XARCH
15941594
#ifdef FEATURE_HW_INTRINSICS
15951595
else if (tree->OperIs(GT_HWINTRINSIC))
15961596
{

src/coreclr/jit/codegenxarch.cpp

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7073,64 +7073,6 @@ void CodeGen::genIntrinsic(GenTree* treeNode)
70737073
genProduceReg(treeNode);
70747074
}
70757075

7076-
//----------------------------------------------------------------------
7077-
// genBitCast - Generate the instruction to move a value between register files
7078-
//
7079-
// Arguments
7080-
// targetType - the destination type
7081-
// targetReg - the destination register
7082-
// srcType - the source type
7083-
// srcReg - the source register
7084-
//
7085-
void CodeGen::genBitCast(var_types targetType, regNumber targetReg, var_types srcType, regNumber srcReg)
7086-
{
7087-
const bool srcFltReg = varTypeUsesFloatReg(srcType) || varTypeIsSIMD(srcType);
7088-
assert(srcFltReg == genIsValidFloatReg(srcReg));
7089-
7090-
const bool dstFltReg = varTypeUsesFloatReg(targetType) || varTypeIsSIMD(targetType);
7091-
assert(dstFltReg == genIsValidFloatReg(targetReg));
7092-
7093-
inst_Mov(targetType, targetReg, srcReg, /* canSkip */ true);
7094-
}
7095-
7096-
//----------------------------------------------------------------------
7097-
// genCodeForBitCast - Generate code for a GT_BITCAST that is not contained
7098-
//
7099-
// Arguments
7100-
// treeNode - the GT_BITCAST for which we're generating code
7101-
//
7102-
void CodeGen::genCodeForBitCast(GenTreeOp* treeNode)
7103-
{
7104-
regNumber targetReg = treeNode->GetRegNum();
7105-
var_types targetType = treeNode->TypeGet();
7106-
GenTree* op1 = treeNode->gtGetOp1();
7107-
genConsumeRegs(op1);
7108-
7109-
if (op1->isContained())
7110-
{
7111-
assert(op1->IsLocal() || op1->isIndir());
7112-
if (genIsRegCandidateLocal(op1))
7113-
{
7114-
unsigned lclNum = op1->AsLclVar()->GetLclNum();
7115-
GetEmitter()->emitIns_R_S(ins_Load(treeNode->TypeGet(), compiler->isSIMDTypeLocalAligned(lclNum)),
7116-
emitTypeSize(treeNode), targetReg, lclNum, 0);
7117-
}
7118-
else
7119-
{
7120-
op1->gtType = treeNode->TypeGet();
7121-
op1->SetRegNum(targetReg);
7122-
op1->ClearContained();
7123-
JITDUMP("Changing type of BITCAST source to load directly.");
7124-
genCodeForTreeNode(op1);
7125-
}
7126-
}
7127-
else
7128-
{
7129-
genBitCast(targetType, targetReg, op1->TypeGet(), op1->GetRegNum());
7130-
}
7131-
genProduceReg(treeNode);
7132-
}
7133-
71347076
//-------------------------------------------------------------------------- //
71357077
// getBaseVarForPutArgStk - returns the baseVarNum for passing a stack arg.
71367078
//

src/coreclr/jit/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7630,11 +7630,13 @@ class Compiler
76307630
#if defined(TARGET_AMD64)
76317631
static bool varTypeNeedsPartialCalleeSave(var_types type)
76327632
{
7633+
assert(type != TYP_STRUCT);
76337634
return (type == TYP_SIMD32);
76347635
}
76357636
#elif defined(TARGET_ARM64)
76367637
static bool varTypeNeedsPartialCalleeSave(var_types type)
76377638
{
7639+
assert(type != TYP_STRUCT);
76387640
// ARM64 ABI FP Callee save registers only require Callee to save lower 8 Bytes
76397641
// For SIMD types longer than 8 bytes Caller is responsible for saving and restoring Upper bytes.
76407642
return ((type == TYP_SIMD16) || (type == TYP_SIMD12));

src/coreclr/jit/jitconfigvalues.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -556,12 +556,7 @@ CONFIG_INTEGER(JitSaveFpLrWithCalleeSavedRegisters, W("JitSaveFpLrWithCalleeSave
556556
#endif // defined(TARGET_ARM64)
557557
#endif // DEBUG
558558

559-
#if defined(TARGET_WINDOWS) && defined(TARGET_XARCH)
560559
CONFIG_INTEGER(JitEnregStructLocals, W("JitEnregStructLocals"), 1) // Allow to enregister locals with struct type.
561-
#else
562-
CONFIG_INTEGER(JitEnregStructLocals, W("JitEnregStructLocals"), 0) // Don't allow to enregister locals with struct type
563-
// yet.
564-
#endif
565560

566561
#undef CONFIG_INTEGER
567562
#undef CONFIG_STRING

0 commit comments

Comments
 (0)