Skip to content

Commit 730df5a

Browse files
[Support] Add KnownBits::computeForSubBorrow (#67788)
- [Support] Add KnownBits::computeForSubBorrow - [CodeGen] Implement USUBC, USUBO_CARRY, and SSUBO_CARRY with KnownBits::computeForSubBorrow - [CodeGen] Compute unknown bits for Carry/Borrow for ADD/SUB - [CodeGen] Compute known bits of Carry/Borrow for UADDO, SADDO, USUBO, and SSUBO Fixes #65893 --------- Co-authored-by: Shafik Yaghmour <[email protected]>
1 parent ae89497 commit 730df5a

File tree

5 files changed

+171
-13
lines changed

5 files changed

+171
-13
lines changed

llvm/include/llvm/Support/KnownBits.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,11 @@ struct KnownBits {
332332
static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS,
333333
KnownBits RHS);
334334

335+
/// Compute known bits results from subtracting RHS from LHS with 1-bit
336+
/// Borrow.
337+
static KnownBits computeForSubBorrow(const KnownBits &LHS, KnownBits RHS,
338+
const KnownBits &Borrow);
339+
335340
/// Compute knownbits resulting from llvm.sadd.sat(LHS, RHS)
336341
static KnownBits sadd_sat(const KnownBits &LHS, const KnownBits &RHS);
337342

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3741,14 +3741,19 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
37413741
assert(Op.getResNo() == 0 &&
37423742
"We only compute knownbits for the difference here.");
37433743

3744-
// TODO: Compute influence of the carry operand.
3745-
if (Opcode == ISD::USUBO_CARRY || Opcode == ISD::SSUBO_CARRY)
3746-
break;
3744+
// With USUBO_CARRY and SSUBO_CARRY a borrow bit may be added in.
3745+
KnownBits Borrow(1);
3746+
if (Opcode == ISD::USUBO_CARRY || Opcode == ISD::SSUBO_CARRY) {
3747+
Borrow = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1);
3748+
// Borrow has bit width 1
3749+
Borrow = Borrow.trunc(1);
3750+
} else {
3751+
Borrow.setAllZero();
3752+
}
37473753

37483754
Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
37493755
Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
3750-
Known = KnownBits::computeForAddSub(/* Add */ false, /* NSW */ false,
3751-
Known, Known2);
3756+
Known = KnownBits::computeForSubBorrow(Known, Known2, Borrow);
37523757
break;
37533758
}
37543759
case ISD::UADDO:
@@ -3773,15 +3778,13 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
37733778
if (Opcode == ISD::ADDE)
37743779
// Can't track carry from glue, set carry to unknown.
37753780
Carry.resetAll();
3776-
else if (Opcode == ISD::UADDO_CARRY || Opcode == ISD::SADDO_CARRY)
3777-
// TODO: Compute known bits for the carry operand. Not sure if it is worth
3778-
// the trouble (how often will we find a known carry bit). And I haven't
3779-
// tested this very much yet, but something like this might work:
3780-
// Carry = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1);
3781-
// Carry = Carry.zextOrTrunc(1, false);
3782-
Carry.resetAll();
3783-
else
3781+
else if (Opcode == ISD::UADDO_CARRY || Opcode == ISD::SADDO_CARRY) {
3782+
Carry = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1);
3783+
// Carry has bit width 1
3784+
Carry = Carry.trunc(1);
3785+
} else {
37843786
Carry.setAllZero();
3787+
}
37853788

37863789
Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
37873790
Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);

llvm/lib/Support/KnownBits.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ KnownBits KnownBits::computeForAddSub(bool Add, bool NSW,
8585
return KnownOut;
8686
}
8787

88+
KnownBits KnownBits::computeForSubBorrow(const KnownBits &LHS, KnownBits RHS,
89+
const KnownBits &Borrow) {
90+
assert(Borrow.getBitWidth() == 1 && "Borrow must be 1-bit");
91+
92+
// LHS - RHS = LHS + ~RHS + 1
93+
// Carry 1 - Borrow in ::computeForAddCarry
94+
std::swap(RHS.Zero, RHS.One);
95+
return ::computeForAddCarry(LHS, RHS,
96+
/*CarryZero=*/Borrow.One.getBoolValue(),
97+
/*CarryOne=*/Borrow.Zero.getBoolValue());
98+
}
99+
88100
KnownBits KnownBits::sextInReg(unsigned SrcBitWidth) const {
89101
unsigned BitWidth = getBitWidth();
90102
assert(0 < SrcBitWidth && SrcBitWidth <= BitWidth &&

llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,59 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_ADD) {
254254
EXPECT_EQ(Known.One, APInt(8, 0x55));
255255
}
256256

257+
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
258+
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_UADDO_CARRY) {
259+
SDLoc Loc;
260+
auto IntVT = EVT::getIntegerVT(Context, 8);
261+
auto UnknownOp = DAG->getRegister(0, IntVT);
262+
auto Mask_Zero = DAG->getConstant(0x28, Loc, IntVT);
263+
auto Mask_One = DAG->getConstant(0x20, Loc, IntVT);
264+
auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask_Zero, UnknownOp);
265+
N0 = DAG->getNode(ISD::OR, Loc, IntVT, Mask_One, N0);
266+
auto N1 = DAG->getConstant(0x65, Loc, IntVT);
267+
268+
KnownBits Known;
269+
270+
auto UnknownBorrow = DAG->getRegister(1, IntVT);
271+
auto OpUnknownBorrow =
272+
DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, UnknownBorrow);
273+
// N0 = 0010?000
274+
// N1 = 01100101
275+
// B = ?
276+
// =>
277+
// Known.Zero = 01110000 (0x70)
278+
// Known.One = 10000100 (0x84)
279+
Known = DAG->computeKnownBits(OpUnknownBorrow);
280+
EXPECT_EQ(Known.Zero, APInt(8, 0x70));
281+
EXPECT_EQ(Known.One, APInt(8, 0x84));
282+
283+
auto ZeroBorrow = DAG->getConstant(0x0, Loc, IntVT);
284+
auto OpZeroBorrow =
285+
DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, ZeroBorrow);
286+
// N0 = 0010?000
287+
// N1 = 01100101
288+
// B = 0
289+
// =>
290+
// Known.Zero = 01110010 (0x72)
291+
// Known.One = 10000101 (0x85)
292+
Known = DAG->computeKnownBits(OpZeroBorrow);
293+
EXPECT_EQ(Known.Zero, APInt(8, 0x72));
294+
EXPECT_EQ(Known.One, APInt(8, 0x85));
295+
296+
auto OneBorrow = DAG->getConstant(0x1, Loc, IntVT);
297+
auto OpOneBorrow =
298+
DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, OneBorrow);
299+
// N0 = 0010?000
300+
// N1 = 01100101
301+
// B = 1
302+
// =>
303+
// Known.Zero = 01110001 (0x71)
304+
// Known.One = 10000110 (0x86)
305+
Known = DAG->computeKnownBits(OpOneBorrow);
306+
EXPECT_EQ(Known.Zero, APInt(8, 0x71));
307+
EXPECT_EQ(Known.One, APInt(8, 0x86));
308+
}
309+
257310
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
258311
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_SUB) {
259312
SDLoc Loc;
@@ -273,6 +326,60 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_SUB) {
273326
EXPECT_EQ(Known.One, APInt(8, 0x1));
274327
}
275328

329+
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
330+
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_USUBO_CARRY) {
331+
SDLoc Loc;
332+
auto IntVT = EVT::getIntegerVT(Context, 8);
333+
auto N0 = DAG->getConstant(0x5a, Loc, IntVT);
334+
auto UnknownOp = DAG->getRegister(0, IntVT); // ????????
335+
auto Mask1_Zero = DAG->getConstant(0x8, Loc, IntVT); // 00001000
336+
auto Mask1_One = DAG->getConstant(0x20, Loc, IntVT); // 00100000
337+
// N1 = (???????? & 00001000) | 00100000 = 0010?000
338+
auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask1_Zero, UnknownOp);
339+
N1 = DAG->getNode(ISD::OR, Loc, IntVT, Mask1_One, N1);
340+
341+
KnownBits Known;
342+
343+
auto UnknownBorrow = DAG->getRegister(1, IntVT);
344+
auto OpUnknownBorrow =
345+
DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, UnknownBorrow);
346+
// N0 = 01011010
347+
// N1 = 0010?000
348+
// B = ?
349+
// =>
350+
// Known.Zero = 11000100 (0xc4)
351+
// Known.One = 00110000 (0x30)
352+
Known = DAG->computeKnownBits(OpUnknownBorrow);
353+
EXPECT_EQ(Known.Zero, APInt(8, 0xc4));
354+
EXPECT_EQ(Known.One, APInt(8, 0x30));
355+
356+
auto ZeroBorrow = DAG->getConstant(0x0, Loc, IntVT);
357+
auto OpZeroBorrow =
358+
DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, ZeroBorrow);
359+
// N0 = 01011010
360+
// N1 = 0010?000
361+
// B = 0
362+
// =>
363+
// Known.Zero = 11000101 (0xc5)
364+
// Known.One = 00110010 (0x32)
365+
Known = DAG->computeKnownBits(OpZeroBorrow);
366+
EXPECT_EQ(Known.Zero, APInt(8, 0xc5));
367+
EXPECT_EQ(Known.One, APInt(8, 0x32));
368+
369+
auto OneBorrow = DAG->getConstant(0x1, Loc, IntVT);
370+
auto OpOneBorrow =
371+
DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, OneBorrow);
372+
// N0 = 01011010
373+
// N1 = 0010?000
374+
// B = 1
375+
// =>
376+
// Known.Zero = 11000110 (0xc6)
377+
// Known.One = 00110001 (0x31)
378+
Known = DAG->computeKnownBits(OpOneBorrow);
379+
EXPECT_EQ(Known.Zero, APInt(8, 0xc6));
380+
EXPECT_EQ(Known.One, APInt(8, 0x31));
381+
}
382+
276383
TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_BUILD_VECTOR) {
277384
TargetLowering TL(*TM);
278385

llvm/unittests/Support/KnownBitsTest.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,37 @@ TEST(KnownBitsTest, AddSubExhaustive) {
213213
TestAddSubExhaustive(false);
214214
}
215215

216+
TEST(KnownBitsTest, SubBorrowExhaustive) {
217+
unsigned Bits = 4;
218+
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
219+
ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
220+
ForeachKnownBits(1, [&](const KnownBits &KnownBorrow) {
221+
// Explicitly compute known bits of the subtraction by trying all
222+
// possibilities.
223+
KnownBits Known(Bits);
224+
Known.Zero.setAllBits();
225+
Known.One.setAllBits();
226+
ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
227+
ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
228+
ForeachNumInKnownBits(KnownBorrow, [&](const APInt &Borrow) {
229+
APInt Sub = N1 - N2;
230+
if (Borrow.getBoolValue())
231+
--Sub;
232+
233+
Known.One &= Sub;
234+
Known.Zero &= ~Sub;
235+
});
236+
});
237+
});
238+
239+
KnownBits KnownComputed =
240+
KnownBits::computeForSubBorrow(Known1, Known2, KnownBorrow);
241+
EXPECT_EQ(Known, KnownComputed);
242+
});
243+
});
244+
});
245+
}
246+
216247
TEST(KnownBitsTest, BinaryExhaustive) {
217248
testBinaryOpExhaustive(
218249
[](const KnownBits &Known1, const KnownBits &Known2) {

0 commit comments

Comments
 (0)