Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[arm64] JIT: Recognize sbfiz/ubfiz idioms #61045

Merged
merged 14 commits into from
Nov 4, 2021
29 changes: 26 additions & 3 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1614,23 +1614,46 @@ void CodeGen::genCodeForShift(GenTree* tree)
genTreeOps oper = tree->OperGet();
instruction ins = genGetInsForOper(oper, targetType);
emitAttr size = emitActualTypeSize(tree);
regNumber dstReg = tree->GetRegNum();

assert(tree->GetRegNum() != REG_NA);
assert(dstReg != REG_NA);

genConsumeOperands(tree->AsOp());

GenTree* operand = tree->gtGetOp1();
GenTree* shiftBy = tree->gtGetOp2();
if (!shiftBy->IsCnsIntOrI())
{
GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftBy->GetRegNum());
GetEmitter()->emitIns_R_R_R(ins, size, dstReg, operand->GetRegNum(), shiftBy->GetRegNum());
}
else
{
unsigned immWidth = emitter::getBitWidth(size); // For ARM64, immWidth will be set to 32 or 64
unsigned shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal & (immWidth - 1);

GetEmitter()->emitIns_R_R_I(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftByImm);
#ifdef TARGET_ARM64
// Check if we can recognize ubfiz/sbfiz idiom in LSH(CAST(X), CNS) pattern
if (tree->gtGetOp1()->OperIs(GT_CAST) && tree->gtGetOp1()->isContained())
{
GenTreeCast* cast = tree->gtGetOp1()->AsCast();
GenTree* castOp = cast->CastOp();

unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE
: genTypeSize(castOp) * BITS_PER_BYTE;
unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE;

assert(srcBits < dstBits);
assert((shiftByImm > 0) && (shiftByImm < srcBits));

const bool isUnsigned = cast->IsUnsigned() || varTypeIsUnsigned(cast->CastToType());
GetEmitter()->emitIns_R_R_I_I(isUnsigned ? INS_ubfiz : INS_sbfiz, size, dstReg, castOp->GetRegNum(),
(int)shiftByImm, (int)srcBits);
}
else
#endif
{
GetEmitter()->emitIns_R_R_I(ins, size, dstReg, operand->GetRegNum(), shiftByImm);
}
}

genProduceReg(tree);
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,7 @@ void CodeGen::genConsumeRegs(GenTree* tree)
}
#endif // FEATURE_HW_INTRINSICS
#endif // TARGET_XARCH
else if (tree->OperIs(GT_BITCAST))
else if (tree->OperIs(GT_BITCAST, GT_CAST))
{
genConsumeReg(tree->gtGetOp1());
}
Expand Down
30 changes: 30 additions & 0 deletions src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5753,6 +5753,36 @@ void Lowering::LowerShift(GenTreeOp* shift)
shift->gtOp2->ClearContained();
}
ContainCheckShiftRotate(shift);

#ifdef TARGET_ARM64
EgorBo marked this conversation as resolved.
Show resolved Hide resolved
// Try to recognize ubfiz/sbfiz idiom in LSH(CAST(X), CNS) tree
if (comp->opts.OptimizationEnabled() && shift->OperIs(GT_LSH) && shift->gtGetOp1()->OperIs(GT_CAST) &&
shift->gtGetOp2()->IsCnsIntOrI() && !shift->isContained() && varTypeIsIntegral(shift))
EgorBo marked this conversation as resolved.
Show resolved Hide resolved
{
GenTreeIntCon* cns = shift->gtGetOp2()->AsIntCon();
EgorBo marked this conversation as resolved.
Show resolved Hide resolved
GenTreeCast* cast = shift->gtGetOp1()->AsCast();

if (!cast->isContained() && !cast->IsRegOptional() && !cast->gtOverflow() &&
// Smaller CastOp is most likely an IND(X) node which is lowered to a zero-extend load
cast->CastOp()->TypeIs(TYP_LONG, TYP_INT))
{
// Cast is either "TYP_LONG <- TYP_INT" or "TYP_INT <- %SMALL_INT% <- TYP_INT" (signed or unsigned)

unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE
: genTypeSize(cast->CastOp()) * BITS_PER_BYTE;
unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE;

assert(!cast->CastOp()->isContained());

// It has to be an upcast and CNS must be in [1..srcBits) range
if ((srcBits < dstBits) && ((UINT32)cns->IconValue() < srcBits))
{
JITDUMP("Recognized ubfix/sbfix pattern in LSH(CAST, CNS), marking CAST node as contained.");
MakeSrcContained(shift, cast);
}
}
}
#endif
}

void Lowering::WidenSIMD12IfNecessary(GenTreeLclVarCommon* node)
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/lsrabuild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3071,6 +3071,10 @@ int LinearScan::BuildOperandUses(GenTree* node, regMaskTP candidates)
return 1;
}
#endif // FEATURE_HW_INTRINSICS
if (node->OperIs(GT_CAST))
{
return BuildOperandUses(node->gtGetOp1(), candidates);
}

return 0;
}
Expand Down
Loading