Skip to content

Commit bfc5ebc

Browse files
authored
[arm64] JIT: Recognize sbfiz/ubfiz idioms (#61045)
1 parent 22f0683 commit bfc5ebc

File tree

8 files changed

+807
-4
lines changed

8 files changed

+807
-4
lines changed

src/coreclr/jit/codegen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12481248
void genCodeForJumpTrue(GenTreeOp* jtrue);
12491249
#ifdef TARGET_ARM64
12501250
void genCodeForJumpCompare(GenTreeOp* tree);
1251+
void genCodeForBfiz(GenTreeOp* tree);
12511252
#endif // TARGET_ARM64
12521253

12531254
#if defined(FEATURE_EH_FUNCLETS)

src/coreclr/jit/codegenarm64.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9564,4 +9564,30 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind)
95649564
}
95659565
}
95669566

9567+
//------------------------------------------------------------------------
9568+
// genCodeForBfiz: Generates the code sequence for a GenTree node that
9569+
// represents a bitfield insert in zero with sign/zero extension.
9570+
//
9571+
// Arguments:
9572+
// tree - the bitfield insert in zero node.
9573+
//
9574+
void CodeGen::genCodeForBfiz(GenTreeOp* tree)
9575+
{
9576+
assert(tree->OperIs(GT_BFIZ));
9577+
9578+
emitAttr size = emitActualTypeSize(tree);
9579+
unsigned shiftBy = (unsigned)tree->gtGetOp2()->AsIntCon()->IconValue();
9580+
unsigned shiftByImm = shiftBy & (emitter::getBitWidth(size) - 1);
9581+
GenTreeCast* cast = tree->gtGetOp1()->AsCast();
9582+
GenTree* castOp = cast->CastOp();
9583+
9584+
genConsumeRegs(castOp);
9585+
unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE
9586+
: genTypeSize(castOp) * BITS_PER_BYTE;
9587+
const bool isUnsigned = cast->IsUnsigned() || varTypeIsUnsigned(cast->CastToType());
9588+
GetEmitter()->emitIns_R_R_I_I(isUnsigned ? INS_ubfiz : INS_sbfiz, size, tree->GetRegNum(), castOp->GetRegNum(),
9589+
(int)shiftByImm, (int)srcBits);
9590+
genProduceReg(tree);
9591+
}
9592+
95679593
#endif // TARGET_ARM64

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
312312
case GT_SWAP:
313313
genCodeForSwap(treeNode->AsOp());
314314
break;
315+
316+
case GT_BFIZ:
317+
genCodeForBfiz(treeNode->AsOp());
318+
break;
315319
#endif // TARGET_ARM64
316320

317321
case GT_JMP:
@@ -1614,23 +1618,23 @@ void CodeGen::genCodeForShift(GenTree* tree)
16141618
genTreeOps oper = tree->OperGet();
16151619
instruction ins = genGetInsForOper(oper, targetType);
16161620
emitAttr size = emitActualTypeSize(tree);
1621+
regNumber dstReg = tree->GetRegNum();
16171622

1618-
assert(tree->GetRegNum() != REG_NA);
1623+
assert(dstReg != REG_NA);
16191624

16201625
genConsumeOperands(tree->AsOp());
16211626

16221627
GenTree* operand = tree->gtGetOp1();
16231628
GenTree* shiftBy = tree->gtGetOp2();
16241629
if (!shiftBy->IsCnsIntOrI())
16251630
{
1626-
GetEmitter()->emitIns_R_R_R(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftBy->GetRegNum());
1631+
GetEmitter()->emitIns_R_R_R(ins, size, dstReg, operand->GetRegNum(), shiftBy->GetRegNum());
16271632
}
16281633
else
16291634
{
16301635
unsigned immWidth = emitter::getBitWidth(size); // For ARM64, immWidth will be set to 32 or 64
16311636
unsigned shiftByImm = (unsigned)shiftBy->AsIntCon()->gtIconVal & (immWidth - 1);
1632-
1633-
GetEmitter()->emitIns_R_R_I(ins, size, tree->GetRegNum(), operand->GetRegNum(), shiftByImm);
1637+
GetEmitter()->emitIns_R_R_I(ins, size, dstReg, operand->GetRegNum(), shiftByImm);
16341638
}
16351639

16361640
genProduceReg(tree);

src/coreclr/jit/gtlist.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ GTNODE(PHI_ARG , GenTreePhiArg ,0,(GTK_LEAF|GTK_LOCAL)) // phi
282282

283283
GTNODE(JMPTABLE , GenTree ,0, (GTK_LEAF|GTK_NOCONTAIN)) // Generates the jump table for switches
284284
GTNODE(SWITCH_TABLE , GenTreeOp ,0, (GTK_BINOP|GTK_NOVALUE)) // Jump Table based switch construct
285+
#ifdef TARGET_ARM64
286+
GTNODE(BFIZ, GenTreeBfiz ,0, GTK_BINOP) // Bitfield Insert in Zero
287+
#endif
285288

286289
//-----------------------------------------------------------------------------
287290
// Nodes used only within the code generator:

src/coreclr/jit/lower.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5753,6 +5753,35 @@ void Lowering::LowerShift(GenTreeOp* shift)
57535753
shift->gtOp2->ClearContained();
57545754
}
57555755
ContainCheckShiftRotate(shift);
5756+
5757+
#ifdef TARGET_ARM64
5758+
// Try to recognize ubfiz/sbfiz idiom in LSH(CAST(X), CNS) tree
5759+
if (comp->opts.OptimizationEnabled() && shift->OperIs(GT_LSH) && shift->gtGetOp1()->OperIs(GT_CAST) &&
5760+
shift->gtGetOp2()->IsCnsIntOrI() && !shift->isContained())
5761+
{
5762+
GenTreeIntCon* cns = shift->gtGetOp2()->AsIntCon();
5763+
GenTreeCast* cast = shift->gtGetOp1()->AsCast();
5764+
5765+
if (!cast->isContained() && !cast->IsRegOptional() && !cast->gtOverflow() &&
5766+
// Smaller CastOp is most likely an IND(X) node which is lowered to a zero-extend load
5767+
cast->CastOp()->TypeIs(TYP_LONG, TYP_INT))
5768+
{
5769+
// Cast is either "TYP_LONG <- TYP_INT" or "TYP_INT <- %SMALL_INT% <- TYP_INT" (signed or unsigned)
5770+
unsigned dstBits = genTypeSize(cast) * BITS_PER_BYTE;
5771+
unsigned srcBits = varTypeIsSmall(cast->CastToType()) ? genTypeSize(cast->CastToType()) * BITS_PER_BYTE
5772+
: genTypeSize(cast->CastOp()) * BITS_PER_BYTE;
5773+
assert(!cast->CastOp()->isContained());
5774+
5775+
// It has to be an upcast and CNS must be in [1..srcBits) range
5776+
if ((srcBits < dstBits) && ((UINT32)cns->IconValue() < srcBits))
5777+
{
5778+
JITDUMP("Recognized ubfix/sbfix pattern in LSH(CAST, CNS). Changing op to GT_BFIZ");
5779+
shift->ChangeOper(GT_BFIZ);
5780+
MakeSrcContained(shift, cast);
5781+
}
5782+
}
5783+
}
5784+
#endif
57565785
}
57575786

57585787
void Lowering::WidenSIMD12IfNecessary(GenTreeLclVarCommon* node)

src/coreclr/jit/lsraarm64.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ int LinearScan::BuildNode(GenTree* tree)
279279
BuildDef(tree);
280280
break;
281281

282+
case GT_BFIZ:
283+
assert(tree->gtGetOp1()->OperIs(GT_CAST));
284+
srcCount = BuildOperandUses(tree->gtGetOp1()->gtGetOp1());
285+
BuildDef(tree);
286+
break;
287+
282288
case GT_RETURNTRAP:
283289
// this just turns into a compare of its child with an int
284290
// + a conditional call

0 commit comments

Comments
 (0)