Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,7 @@ class CodeGen final : public CodeGenInterface
#endif
void genCodeForTreeNode(GenTree* treeNode);
void genCodeForBinary(GenTreeOp* treeNode);
bool genIsSameLocalVar(GenTree* tree1, GenTree* tree2);

#if defined(TARGET_X86)
void genCodeForLongUMod(GenTreeOp* node);
Expand Down
19 changes: 19 additions & 0 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,25 @@ regMaskTP CodeGenInterface::genGetRegMask(GenTree* tree)
return regMask;
}

//------------------------------------------------------------------------
// genIsSameLocalVar:
// Check if two trees represent the same scalar local value.
//
// Arguments:
// op1 - first tree
// op2 - second tree
//
// Returns:
// True if so.
//
bool CodeGen::genIsSameLocalVar(GenTree* op1, GenTree* op2)
{
GenTree* op1Skip = op1->gtSkipReloadOrCopy();
GenTree* op2Skip = op2->gtSkipReloadOrCopy();
return op1Skip->OperIs(GT_LCL_VAR) && op2Skip->OperIs(GT_LCL_VAR) &&
(op1Skip->AsLclVar()->GetLclNum() == op2Skip->AsLclVar()->GetLclNum());
}

// The given lclVar is either going live (being born) or dying.
// It might be both going live and dying (that is, it is a dead store) under MinOpts.
// Update regSet.GetMaskVars() accordingly.
Expand Down
23 changes: 3 additions & 20 deletions src/coreclr/jit/codegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1143,28 +1143,11 @@ void CodeGen::genCodeForBinary(GenTreeOp* treeNode)
// In order for this operation to be correct
// we need that op is a commutative operation so
// we can convert it into reg1 = reg1 op reg2 and emit
// the same code as above
// the same code as above. Or we need both operands to
// be the same local.
else if (op2reg == targetReg)
{

#ifdef DEBUG
unsigned lclNum1 = (unsigned)-1;
unsigned lclNum2 = (unsigned)-2;

GenTree* op1Skip = op1->gtSkipReloadOrCopy();
GenTree* op2Skip = op2->gtSkipReloadOrCopy();

if (op1Skip->OperIsLocalRead())
{
lclNum1 = op1Skip->AsLclVarCommon()->GetLclNum();
}
if (op2Skip->OperIsLocalRead())
{
lclNum2 = op2Skip->AsLclVarCommon()->GetLclNum();
}

assert(GenTree::OperIsCommutative(oper) || (lclNum1 == lclNum2));
#endif
assert(GenTree::OperIsCommutative(oper) || genIsSameLocalVar(op1, op2));

dst = op2;
src = op1;
Expand Down
57 changes: 34 additions & 23 deletions src/coreclr/jit/hwintrinsiccodegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
if (isRMW)
{
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

HWIntrinsicImmOpHelper helper(this, intrin.op4, node);
Expand Down Expand Up @@ -412,8 +412,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
if (isRMW)
{
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);
GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op2Reg, op3Reg, 0, opt);
}
Expand Down Expand Up @@ -511,7 +511,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
// If `falseReg` is zero, then move the first operand of `intrinEmbMask` in the
// destination using /Z.

assert((targetReg != embMaskOp2Reg) || (embMaskOp1Reg == embMaskOp2Reg));
assert((targetReg != embMaskOp2Reg) || (embMaskOp1Reg == embMaskOp2Reg) ||
genIsSameLocalVar(intrinEmbMask.op1, intrinEmbMask.op2));
assert(intrin.op3->isContained() || !intrin.op1->IsTrueMask(node->GetSimdBaseType()));
GetEmitter()->emitInsSve_R_R_R(INS_sve_movprfx, emitSize, targetReg, maskReg, embMaskOp1Reg, opt);
}
Expand Down Expand Up @@ -765,14 +766,16 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
switch (intrinEmbMask.id)
{
case NI_Sve_CreateBreakPropagateMask:
assert((targetReg == embMaskOp2Reg) || (targetReg != embMaskOp1Reg));
assert((targetReg == embMaskOp2Reg) || (targetReg != embMaskOp1Reg) ||
genIsSameLocalVar(intrinEmbMask.op1, intrinEmbMask.op2));
GetEmitter()->emitIns_Mov(INS_sve_mov, emitSize, targetReg, embMaskOp2Reg,
/* canSkip */ true);
emitInsHelper(targetReg, maskReg, embMaskOp1Reg);
break;

case NI_Sve_AddSequentialAcross:
assert((targetReg == op1Reg) || (targetReg != embMaskOp2Reg));
assert((targetReg == op1Reg) || (targetReg != embMaskOp2Reg) ||
genIsSameLocalVar(intrinEmbMask.op1, intrinEmbMask.op2));
GetEmitter()->emitIns_Mov(INS_fmov, GetEmitter()->optGetSveElemsize(embOpt), targetReg,
embMaskOp1Reg, /* canSkip */ true);
emitInsHelper(targetReg, maskReg, embMaskOp2Reg);
Expand Down Expand Up @@ -1061,7 +1064,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
if (isRMW)
{
assert((targetReg == op2Reg) || (targetReg != op1Reg));
assert((targetReg == op2Reg) || (targetReg != op1Reg) ||
genIsSameLocalVar(intrin.op1, intrin.op2));
GetEmitter()->emitIns_Mov(ins_Move_Extend(intrin.op2->TypeGet(), false),
emitTypeSize(node), targetReg, op2Reg,
/* canSkip */ true);
Expand All @@ -1081,7 +1085,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
}
else if (isRMW)
{
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) ||
genIsSameLocalVar(intrin.op1, intrin.op2));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg,
/* canSkip */ true);
GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op2Reg, opt);
Expand All @@ -1099,15 +1104,21 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
if (HWIntrinsicInfo::IsExplicitMaskedOperation(intrin.id))
{
assert((targetReg == op2Reg) || ((targetReg != op1Reg) && (targetReg != op3Reg)));
assert((targetReg == op2Reg) || (targetReg != op1Reg) ||
genIsSameLocalVar(intrin.op2, intrin.op1));
assert((targetReg == op2Reg) || (targetReg != op3Reg) ||
genIsSameLocalVar(intrin.op2, intrin.op3));

GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op2Reg,
/* canSkip */ true);
GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op3Reg, opt);
}
else
{
assert((targetReg == op1Reg) || ((targetReg != op2Reg) && (targetReg != op3Reg)));
assert((targetReg == op1Reg) || (targetReg != op2Reg) ||
genIsSameLocalVar(intrin.op1, intrin.op2));
assert((targetReg == op1Reg) || (targetReg != op3Reg) ||
genIsSameLocalVar(intrin.op1, intrin.op3));

GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg,
/* canSkip */ true);
Expand Down Expand Up @@ -1358,7 +1369,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_AdvSimd_InsertScalar:
{
assert(isRMW);
assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

HWIntrinsicImmOpHelper helper(this, intrin.op2, node);
Expand All @@ -1375,7 +1386,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_AdvSimd_Arm64_InsertSelectedScalar:
{
assert(isRMW);
assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

const int resultIndex = (int)intrin.op2->AsIntCon()->gtIconVal;
Expand All @@ -1387,7 +1398,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_AdvSimd_LoadAndInsertScalar:
{
assert(isRMW);
assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

HWIntrinsicImmOpHelper helper(this, intrin.op2, node);
Expand Down Expand Up @@ -1983,7 +1994,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
break;
}

assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);
GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt);
break;
Expand Down Expand Up @@ -2348,8 +2359,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_Sve_SaturatingIncrementBy8BitElementCount:
{
assert(isRMW);
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op3Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2));
assert((targetReg == op1Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op1, intrin.op3));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

if (intrin.op2->IsCnsIntOrI() && intrin.op3->IsCnsIntOrI())
Expand Down Expand Up @@ -2402,7 +2413,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_Sve_SaturatingIncrementByActiveElementCount:
{
// RMW semantics
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

// Switch instruction if arg1 is unsigned.
Expand Down Expand Up @@ -2442,7 +2453,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
case NI_Sve_ExtractVector:
{
assert(isRMW);
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg, /* canSkip */ true);

HWIntrinsicImmOpHelper helper(this, intrin.op3, node);
Expand All @@ -2461,7 +2472,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
assert(isRMW);
assert(emitter::isFloatReg(op2Reg) == varTypeIsFloating(intrin.baseType));
assert((targetReg == op1Reg) || (targetReg != op2Reg));
assert((targetReg == op1Reg) || (targetReg != op2Reg) || genIsSameLocalVar(intrin.op1, intrin.op2));
GetEmitter()->emitIns_Mov(INS_mov, emitTypeSize(node), targetReg, op1Reg,
/* canSkip */ true);
GetEmitter()->emitInsSve_R_R(ins, emitSize, targetReg, op2Reg, opt);
Expand All @@ -2487,7 +2498,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
assert(isRMW);
assert(HWIntrinsicInfo::IsExplicitMaskedOperation(intrin.id));
assert((targetReg == op2Reg) || (targetReg != op1Reg));
assert((targetReg == op2Reg) || (targetReg != op1Reg) || genIsSameLocalVar(intrin.op2, intrin.op1));
GetEmitter()->emitIns_Mov(INS_sve_mov, emitTypeSize(node), targetReg, op2Reg, /* canSkip */ true);
GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, INS_OPTS_SCALABLE_B);
break;
Expand Down Expand Up @@ -2559,8 +2570,8 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
{
assert(emitter::isFloatReg(targetReg));
assert(varTypeIsFloating(node->gtType) || varTypeIsSIMD(node->gtType));
assert((targetReg == op2Reg) || (targetReg != op1Reg));
assert((targetReg == op2Reg) || (targetReg != op3Reg));
assert((targetReg == op2Reg) || (targetReg != op1Reg) || genIsSameLocalVar(intrin.op2, intrin.op1));
assert((targetReg == op2Reg) || (targetReg != op3Reg) || genIsSameLocalVar(intrin.op2, intrin.op3));

GetEmitter()->emitIns_Mov(INS_sve_mov, EA_SCALABLE, targetReg, op2Reg, /* canSkip */ true, opt);
GetEmitter()->emitInsSve_R_R_R(ins, EA_SCALABLE, targetReg, op1Reg, op3Reg, opt,
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/hwintrinsiccodegenxarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2623,7 +2623,8 @@ void CodeGen::genSse42Intrinsic(GenTreeHWIntrinsic* node, insOpts instOptions)
regNumber op1Reg = op1->GetRegNum();
GenTree* op2 = node->Op(2);

assert(!op2->isUsedFromReg() || (op2->GetRegNum() != targetReg) || (op1Reg == targetReg));
assert(!op2->isUsedFromReg() || (op2->GetRegNum() != targetReg) || (op1Reg == targetReg) ||
genIsSameLocalVar(op1, op2));
emit->emitIns_Mov(INS_mov, emitTypeSize(targetType), targetReg, op1Reg, /* canSkip */ true);

#ifdef TARGET_AMD64
Expand Down
Loading