Skip to content

Commit 76964e3

Browse files
committedAug 9, 2016
[DAGCombiner] Better support for shifting large value type by constants
As detailed on D22726, much of the shift combining code assume constant values will fit into a uint64_t value and calls ConstantSDNode::getZExtValue where it probably shouldn't (leading to asserts). Using APInt directly avoids this problem but we encounter other assertions if we attempt to compare/operate on 2 APInt of different bitwidths. This patch adds a helper function to ensure that 2 APInt values are zero extended as required so that they can be safely used together. I've only added an initial example use for this to the '(SHIFT (SHIFT x, c1), c2) --> (SHIFT x, (ADD c1, c2))' combines. Further cases can easily be added as required. Differential Revision: https://reviews.llvm.org/D23007 llvm-svn: 278141
1 parent 3be8801 commit 76964e3

File tree

2 files changed

+66
-17
lines changed

2 files changed

+66
-17
lines changed
 

‎llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

+42-17
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,15 @@ static SDValue GetNegatedExpression(SDValue Op, SelectionDAG &DAG,
726726
}
727727
}
728728

729+
// APInts must be the same size for most operations, this helper
730+
// function zero extends the shorter of the pair so that they match.
731+
// We provide an Offset so that we can create bitwidths that won't overflow.
732+
static void zeroExtendToMatch(APInt &LHS, APInt &RHS, unsigned Offset = 0) {
733+
unsigned Bits = Offset + std::max(LHS.getBitWidth(), RHS.getBitWidth());
734+
LHS = LHS.zextOrSelf(Bits);
735+
RHS = RHS.zextOrSelf(Bits);
736+
}
737+
729738
// Return true if this node is a setcc, or is a select_cc
730739
// that selects between the target values used for true and false, making it
731740
// equivalent to a setcc. Also, set the incoming LHS, RHS, and CC references to
@@ -4464,13 +4473,18 @@ SDValue DAGCombiner::visitSHL(SDNode *N) {
44644473
// fold (shl (shl x, c1), c2) -> 0 or (shl x, (add c1, c2))
44654474
if (N1C && N0.getOpcode() == ISD::SHL) {
44664475
if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) {
4467-
uint64_t c1 = N0C1->getZExtValue();
4468-
uint64_t c2 = N1C->getZExtValue();
44694476
SDLoc DL(N);
4470-
if (c1 + c2 >= OpSizeInBits)
4477+
APInt c1 = N0C1->getAPIntValue();
4478+
APInt c2 = N1C->getAPIntValue();
4479+
zeroExtendToMatch(c1, c2, 1 /* Overflow Bit */);
4480+
4481+
APInt Sum = c1 + c2;
4482+
if (Sum.uge(OpSizeInBits))
44714483
return DAG.getConstant(0, DL, VT);
4472-
return DAG.getNode(ISD::SHL, DL, VT, N0.getOperand(0),
4473-
DAG.getConstant(c1 + c2, DL, N1.getValueType()));
4484+
4485+
return DAG.getNode(
4486+
ISD::SHL, DL, VT, N0.getOperand(0),
4487+
DAG.getConstant(Sum.getZExtValue(), DL, N1.getValueType()));
44744488
}
44754489
}
44764490

@@ -4656,13 +4670,19 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
46564670

46574671
// fold (sra (sra x, c1), c2) -> (sra x, (add c1, c2))
46584672
if (N1C && N0.getOpcode() == ISD::SRA) {
4659-
if (ConstantSDNode *C1 = isConstOrConstSplat(N0.getOperand(1))) {
4660-
unsigned Sum = N1C->getZExtValue() + C1->getZExtValue();
4661-
if (Sum >= OpSizeInBits)
4662-
Sum = OpSizeInBits - 1;
4673+
if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) {
46634674
SDLoc DL(N);
4664-
return DAG.getNode(ISD::SRA, DL, VT, N0.getOperand(0),
4665-
DAG.getConstant(Sum, DL, N1.getValueType()));
4675+
APInt c1 = N0C1->getAPIntValue();
4676+
APInt c2 = N1C->getAPIntValue();
4677+
zeroExtendToMatch(c1, c2, 1 /* Overflow Bit */);
4678+
4679+
APInt Sum = c1 + c2;
4680+
if (Sum.uge(OpSizeInBits))
4681+
Sum = APInt(OpSizeInBits, OpSizeInBits - 1);
4682+
4683+
return DAG.getNode(
4684+
ISD::SRA, DL, VT, N0.getOperand(0),
4685+
DAG.getConstant(Sum.getZExtValue(), DL, N1.getValueType()));
46664686
}
46674687
}
46684688

@@ -4790,14 +4810,19 @@ SDValue DAGCombiner::visitSRL(SDNode *N) {
47904810

47914811
// fold (srl (srl x, c1), c2) -> 0 or (srl x, (add c1, c2))
47924812
if (N1C && N0.getOpcode() == ISD::SRL) {
4793-
if (ConstantSDNode *N01C = isConstOrConstSplat(N0.getOperand(1))) {
4794-
uint64_t c1 = N01C->getZExtValue();
4795-
uint64_t c2 = N1C->getZExtValue();
4813+
if (ConstantSDNode *N0C1 = isConstOrConstSplat(N0.getOperand(1))) {
47964814
SDLoc DL(N);
4797-
if (c1 + c2 >= OpSizeInBits)
4815+
APInt c1 = N0C1->getAPIntValue();
4816+
APInt c2 = N1C->getAPIntValue();
4817+
zeroExtendToMatch(c1, c2, 1 /* Overflow Bit */);
4818+
4819+
APInt Sum = c1 + c2;
4820+
if (Sum.uge(OpSizeInBits))
47984821
return DAG.getConstant(0, DL, VT);
4799-
return DAG.getNode(ISD::SRL, DL, VT, N0.getOperand(0),
4800-
DAG.getConstant(c1 + c2, DL, N1.getValueType()));
4822+
4823+
return DAG.getNode(
4824+
ISD::SRL, DL, VT, N0.getOperand(0),
4825+
DAG.getConstant(Sum.getZExtValue(), DL, N1.getValueType()));
48014826
}
48024827
}
48034828

‎llvm/test/CodeGen/X86/shift-i128.ll

+24
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,27 @@ entry:
9292
store <2 x i128> %0, <2 x i128>* %r, align 16
9393
ret void
9494
}
95+
96+
define void @test_lshr_v2i128_outofrange_sum(<2 x i128> %x, <2 x i128>* nocapture %r) nounwind {
97+
entry:
98+
%0 = lshr <2 x i128> %x, <i128 -1, i128 -1>
99+
%1 = lshr <2 x i128> %0, <i128 1, i128 1>
100+
store <2 x i128> %1, <2 x i128>* %r, align 16
101+
ret void
102+
}
103+
104+
define void @test_ashr_v2i128_outofrange_sum(<2 x i128> %x, <2 x i128>* nocapture %r) nounwind {
105+
entry:
106+
%0 = ashr <2 x i128> %x, <i128 -1, i128 -1>
107+
%1 = ashr <2 x i128> %0, <i128 1, i128 1>
108+
store <2 x i128> %1, <2 x i128>* %r, align 16
109+
ret void
110+
}
111+
112+
define void @test_shl_v2i128_outofrange_sum(<2 x i128> %x, <2 x i128>* nocapture %r) nounwind {
113+
entry:
114+
%0 = shl <2 x i128> %x, <i128 -1, i128 -1>
115+
%1 = shl <2 x i128> %0, <i128 1, i128 1>
116+
store <2 x i128> %1, <2 x i128>* %r, align 16
117+
ret void
118+
}

0 commit comments

Comments
 (0)
Please sign in to comment.