Skip to content

[ValueTracking] ComputeNumSignBitsImpl - add basic handling of BITCAST nodes #87624

@RKSimon

Description

@RKSimon

At the very least ComputeNumSignBitsImpl should be able to report that if we bitcast from a wider scalar/vector type to a narrow vector element type, and the original wide type was all sign bits then the destination narrow type elements will be all sign bits as well.

SelectionDAG already does this (and quite a bit more, but the "fast case" would be enough):

case ISD::BITCAST: {
if (VT.isScalableVector())
break;
SDValue N0 = Op.getOperand(0);
EVT SrcVT = N0.getValueType();
unsigned SrcBits = SrcVT.getScalarSizeInBits();
// Ignore bitcasts from unsupported types..
if (!(SrcVT.isInteger() || SrcVT.isFloatingPoint()))
break;
// Fast handling of 'identity' bitcasts.
if (VTBits == SrcBits)
return ComputeNumSignBits(N0, DemandedElts, Depth + 1);
bool IsLE = getDataLayout().isLittleEndian();
// Bitcast 'large element' scalar/vector to 'small element' vector.
if ((SrcBits % VTBits) == 0) {
assert(VT.isVector() && "Expected bitcast to vector");
unsigned Scale = SrcBits / VTBits;
APInt SrcDemandedElts =
APIntOps::ScaleBitMask(DemandedElts, NumElts / Scale);
// Fast case - sign splat can be simply split across the small elements.
Tmp = ComputeNumSignBits(N0, SrcDemandedElts, Depth + 1);
if (Tmp == SrcBits)
return VTBits;
// Slow case - determine how far the sign extends into each sub-element.
Tmp2 = VTBits;
for (unsigned i = 0; i != NumElts; ++i)
if (DemandedElts[i]) {
unsigned SubOffset = i % Scale;
SubOffset = (IsLE ? ((Scale - 1) - SubOffset) : SubOffset);
SubOffset = SubOffset * VTBits;
if (Tmp <= SubOffset)
return 1;
Tmp2 = std::min(Tmp2, Tmp - SubOffset);
}
return Tmp2;
}
break;
}

Encountered while fighting bitcasts between SSE intrinsics.

https://alive2.llvm.org/ce/z/NvZpPa

----------------------------------------
define <4 x i2> @src(<1 x i8> %a0, <1 x i8> %a1) {
#0:
  %cmp = icmp sgt <1 x i8> %a0, %a1
  %ext = sext <1 x i1> %cmp to <1 x i8>
  %sub = bitcast <1 x i8> %ext to <4 x i2>
  %sra = ashr <4 x i2> %sub, { 1, 1, 1, 1 }
  ret <4 x i2> %sra
}
=>
define <4 x i2> @tgt(<1 x i8> %a0, <1 x i8> %a1) {
#0:
  %cmp = icmp sgt <1 x i8> %a0, %a1
  %ext = sext <1 x i1> %cmp to <1 x i8>
  %sub = bitcast <1 x i8> %ext to <4 x i2>
  ret <4 x i2> %sub
}
Transformation seems to be correct!

Metadata

Metadata

Assignees

Labels

good first issuehttps://github.com/llvm/llvm-project/contributellvm:instcombineCovers the InstCombine, InstSimplify and AggressiveInstCombine passesllvm:support

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions