Skip to content

Commit 17162b6

Browse files
committed
[KnownBits] Make nuw and nsw support in computeForAddSub optimal
Just some improvements that should hopefully strengthen analysis. Closes #83580
1 parent 61c0677 commit 17162b6

File tree

9 files changed

+178
-69
lines changed

9 files changed

+178
-69
lines changed

llvm/include/llvm/Support/KnownBits.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ struct KnownBits {
6262
/// Returns true if we don't know any bits.
6363
bool isUnknown() const { return Zero.isZero() && One.isZero(); }
6464

65+
/// Returns true if we don't know the sign bit.
66+
bool isSignUnknown() const {
67+
return !Zero.isSignBitSet() && !One.isSignBitSet();
68+
}
69+
6570
/// Resets the known state of all bits.
6671
void resetAll() {
6772
Zero.clearAllBits();
@@ -330,7 +335,7 @@ struct KnownBits {
330335

331336
/// Compute known bits resulting from adding LHS and RHS.
332337
static KnownBits computeForAddSub(bool Add, bool NSW, bool NUW,
333-
const KnownBits &LHS, KnownBits RHS);
338+
const KnownBits &LHS, const KnownBits &RHS);
334339

335340
/// Compute known bits results from subtracting RHS from LHS with 1-bit
336341
/// Borrow.

llvm/lib/Support/KnownBits.cpp

Lines changed: 78 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,89 @@ KnownBits KnownBits::computeForAddCarry(
5454
LHS, RHS, Carry.Zero.getBoolValue(), Carry.One.getBoolValue());
5555
}
5656

57-
KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, bool /*NUW*/,
58-
const KnownBits &LHS, KnownBits RHS) {
59-
KnownBits KnownOut;
60-
if (Add) {
61-
// Sum = LHS + RHS + 0
62-
KnownOut = ::computeForAddCarry(
63-
LHS, RHS, /*CarryZero*/true, /*CarryOne*/false);
64-
} else {
65-
// Sum = LHS + ~RHS + 1
66-
std::swap(RHS.Zero, RHS.One);
67-
KnownOut = ::computeForAddCarry(
68-
LHS, RHS, /*CarryZero*/false, /*CarryOne*/true);
57+
KnownBits KnownBits::computeForAddSub(bool Add, bool NSW, bool NUW,
58+
const KnownBits &LHS,
59+
const KnownBits &RHS) {
60+
unsigned BitWidth = LHS.getBitWidth();
61+
KnownBits KnownOut(BitWidth);
62+
// This can be a relatively expensive helper, so optimistically save some
63+
// work.
64+
if (LHS.isUnknown() && RHS.isUnknown())
65+
return KnownOut;
66+
67+
if (!LHS.isUnknown() && !RHS.isUnknown()) {
68+
if (Add) {
69+
// Sum = LHS + RHS + 0
70+
KnownOut = ::computeForAddCarry(LHS, RHS, /*CarryZero=*/true,
71+
/*CarryOne=*/false);
72+
} else {
73+
// Sum = LHS + ~RHS + 1
74+
KnownBits NotRHS = RHS;
75+
std::swap(NotRHS.Zero, NotRHS.One);
76+
KnownOut = ::computeForAddCarry(LHS, NotRHS, /*CarryZero=*/false,
77+
/*CarryOne=*/true);
78+
}
6979
}
7080

71-
// Are we still trying to solve for the sign bit?
72-
if (!KnownOut.isNegative() && !KnownOut.isNonNegative()) {
73-
if (NSW) {
74-
// Adding two non-negative numbers, or subtracting a negative number from
75-
// a non-negative one, can't wrap into negative.
76-
if (LHS.isNonNegative() && RHS.isNonNegative())
77-
KnownOut.makeNonNegative();
78-
// Adding two negative numbers, or subtracting a non-negative number from
79-
// a negative one, can't wrap into non-negative.
80-
else if (LHS.isNegative() && RHS.isNegative())
81-
KnownOut.makeNegative();
81+
// Handle add/sub given nsw and/or nuw.
82+
if (NUW) {
83+
if (Add) {
84+
// (add nuw X, Y)
85+
APInt MinVal = LHS.getMinValue().uadd_sat(RHS.getMinValue());
86+
// None of the adds can end up overflowing, so min consecutive highbits
87+
// in minimum possible of X + Y must all remain set.
88+
if (NSW) {
89+
unsigned NumBits = MinVal.trunc(BitWidth - 1).countl_one();
90+
// If we have NSW as well, we also know we can't overflow the signbit so
91+
// can start counting from 1 bit back.
92+
KnownOut.One.setBits(BitWidth - 1 - NumBits, BitWidth - 1);
93+
}
94+
KnownOut.One.setHighBits(MinVal.countl_one());
95+
} else {
96+
// (sub nuw X, Y)
97+
APInt MaxVal = LHS.getMaxValue().usub_sat(RHS.getMinValue());
98+
// None of the subs can overflow at any point, so any common high bits
99+
// will subtract away and result in zeros.
100+
if (NSW) {
101+
// If we have NSW as well, we also know we can't overflow the signbit so
102+
// can start counting from 1 bit back.
103+
unsigned NumBits = MaxVal.trunc(BitWidth - 1).countl_zero();
104+
KnownOut.Zero.setBits(BitWidth - 1 - NumBits, BitWidth - 1);
105+
}
106+
KnownOut.Zero.setHighBits(MaxVal.countl_zero());
107+
}
108+
}
109+
110+
if (NSW) {
111+
APInt MinVal;
112+
APInt MaxVal;
113+
if (Add) {
114+
// (add nsw X, Y)
115+
MinVal = LHS.getSignedMinValue().sadd_sat(RHS.getSignedMinValue());
116+
MaxVal = LHS.getSignedMaxValue().sadd_sat(RHS.getSignedMaxValue());
117+
} else {
118+
// (sub nsw X, Y)
119+
MinVal = LHS.getSignedMinValue().ssub_sat(RHS.getSignedMaxValue());
120+
MaxVal = LHS.getSignedMaxValue().ssub_sat(RHS.getSignedMinValue());
121+
}
122+
if (MinVal.isNonNegative()) {
123+
// If min is non-negative, result will always be non-neg (can't overflow
124+
// around).
125+
unsigned NumBits = MinVal.trunc(BitWidth - 1).countl_one();
126+
KnownOut.One.setBits(BitWidth - 1 - NumBits, BitWidth - 1);
127+
KnownOut.Zero.setSignBit();
128+
}
129+
if (MaxVal.isNegative()) {
130+
// If max is negative, result will always be neg (can't overflow around).
131+
unsigned NumBits = MaxVal.trunc(BitWidth - 1).countl_zero();
132+
KnownOut.Zero.setBits(BitWidth - 1 - NumBits, BitWidth - 1);
133+
KnownOut.One.setSignBit();
82134
}
83135
}
84136

137+
// Just return 0 if the nsw/nuw is violated and we have poison.
138+
if (KnownOut.hasConflict())
139+
KnownOut.setAllZero();
85140
return KnownOut;
86141
}
87142

llvm/test/CodeGen/AArch64/sve-cmp-folds.ll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,12 @@ define i1 @foo_last(<vscale x 4 x float> %a, <vscale x 4 x float> %b) {
114114
; CHECK-LABEL: foo_last:
115115
; CHECK: // %bb.0:
116116
; CHECK-NEXT: ptrue p0.s
117-
; CHECK-NEXT: fcmeq p1.s, p0/z, z0.s, z1.s
118-
; CHECK-NEXT: ptest p0, p1.b
119-
; CHECK-NEXT: cset w0, lo
117+
; CHECK-NEXT: mov x8, #-1 // =0xffffffffffffffff
118+
; CHECK-NEXT: whilels p1.s, xzr, x8
119+
; CHECK-NEXT: fcmeq p0.s, p0/z, z0.s, z1.s
120+
; CHECK-NEXT: mov z0.s, p0/z, #1 // =0x1
121+
; CHECK-NEXT: lastb w8, p1, z0.s
122+
; CHECK-NEXT: and w0, w8, #0x1
120123
; CHECK-NEXT: ret
121124
%vcond = fcmp oeq <vscale x 4 x float> %a, %b
122125
%vscale = call i64 @llvm.vscale.i64()

llvm/test/CodeGen/AArch64/sve-extract-element.ll

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,11 @@ define i1 @test_lane9_8xi1(<vscale x 8 x i1> %a) #0 {
614614
define i1 @test_last_8xi1(<vscale x 8 x i1> %a) #0 {
615615
; CHECK-LABEL: test_last_8xi1:
616616
; CHECK: // %bb.0:
617-
; CHECK-NEXT: ptrue p1.h
618-
; CHECK-NEXT: ptest p1, p0.b
619-
; CHECK-NEXT: cset w0, lo
617+
; CHECK-NEXT: mov x8, #-1 // =0xffffffffffffffff
618+
; CHECK-NEXT: mov z0.h, p0/z, #1 // =0x1
619+
; CHECK-NEXT: whilels p1.h, xzr, x8
620+
; CHECK-NEXT: lastb w8, p1, z0.h
621+
; CHECK-NEXT: and w0, w8, #0x1
620622
; CHECK-NEXT: ret
621623
%vscale = call i64 @llvm.vscale.i64()
622624
%shl = shl nuw nsw i64 %vscale, 3

llvm/test/CodeGen/AMDGPU/ds-sub-offset.ll

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -137,49 +137,46 @@ define amdgpu_kernel void @write_ds_sub_max_offset_global_clamp_bit(float %dummy
137137
; CI: ; %bb.0:
138138
; CI-NEXT: s_load_dword s0, s[0:1], 0x0
139139
; CI-NEXT: s_mov_b64 vcc, 0
140-
; CI-NEXT: v_not_b32_e32 v0, v0
141-
; CI-NEXT: v_lshlrev_b32_e32 v0, 2, v0
142-
; CI-NEXT: v_mov_b32_e32 v2, 0x7b
140+
; CI-NEXT: v_mov_b32_e32 v1, 0x7b
141+
; CI-NEXT: v_mov_b32_e32 v2, 0
142+
; CI-NEXT: s_mov_b32 m0, -1
143143
; CI-NEXT: s_waitcnt lgkmcnt(0)
144-
; CI-NEXT: v_mov_b32_e32 v1, s0
145-
; CI-NEXT: v_div_fmas_f32 v1, v1, v1, v1
144+
; CI-NEXT: v_mov_b32_e32 v0, s0
145+
; CI-NEXT: v_div_fmas_f32 v0, v0, v0, v0
146146
; CI-NEXT: s_mov_b32 s0, 0
147-
; CI-NEXT: s_mov_b32 m0, -1
148147
; CI-NEXT: s_mov_b32 s3, 0xf000
149148
; CI-NEXT: s_mov_b32 s2, -1
150149
; CI-NEXT: s_mov_b32 s1, s0
151-
; CI-NEXT: ds_write_b32 v0, v2 offset:65532
152-
; CI-NEXT: buffer_store_dword v1, off, s[0:3], 0
150+
; CI-NEXT: ds_write_b32 v2, v1
151+
; CI-NEXT: buffer_store_dword v0, off, s[0:3], 0
153152
; CI-NEXT: s_waitcnt vmcnt(0)
154153
; CI-NEXT: s_endpgm
155154
;
156155
; GFX9-LABEL: write_ds_sub_max_offset_global_clamp_bit:
157156
; GFX9: ; %bb.0:
158157
; GFX9-NEXT: s_load_dword s0, s[0:1], 0x0
159158
; GFX9-NEXT: s_mov_b64 vcc, 0
160-
; GFX9-NEXT: v_not_b32_e32 v0, v0
161-
; GFX9-NEXT: v_lshlrev_b32_e32 v3, 2, v0
162-
; GFX9-NEXT: v_mov_b32_e32 v4, 0x7b
159+
; GFX9-NEXT: v_mov_b32_e32 v3, 0x7b
160+
; GFX9-NEXT: v_mov_b32_e32 v4, 0
161+
; GFX9-NEXT: ds_write_b32 v4, v3
163162
; GFX9-NEXT: s_waitcnt lgkmcnt(0)
164-
; GFX9-NEXT: v_mov_b32_e32 v1, s0
165-
; GFX9-NEXT: v_div_fmas_f32 v2, v1, v1, v1
163+
; GFX9-NEXT: v_mov_b32_e32 v0, s0
164+
; GFX9-NEXT: v_div_fmas_f32 v2, v0, v0, v0
166165
; GFX9-NEXT: v_mov_b32_e32 v0, 0
167166
; GFX9-NEXT: v_mov_b32_e32 v1, 0
168-
; GFX9-NEXT: ds_write_b32 v3, v4 offset:65532
169167
; GFX9-NEXT: global_store_dword v[0:1], v2, off
170168
; GFX9-NEXT: s_waitcnt vmcnt(0)
171169
; GFX9-NEXT: s_endpgm
172170
;
173171
; GFX10-LABEL: write_ds_sub_max_offset_global_clamp_bit:
174172
; GFX10: ; %bb.0:
175173
; GFX10-NEXT: s_load_dword s0, s[0:1], 0x0
176-
; GFX10-NEXT: v_not_b32_e32 v0, v0
177174
; GFX10-NEXT: s_mov_b32 vcc_lo, 0
178-
; GFX10-NEXT: v_mov_b32_e32 v3, 0x7b
179-
; GFX10-NEXT: v_lshlrev_b32_e32 v2, 2, v0
180175
; GFX10-NEXT: v_mov_b32_e32 v0, 0
176+
; GFX10-NEXT: v_mov_b32_e32 v2, 0x7b
177+
; GFX10-NEXT: v_mov_b32_e32 v3, 0
181178
; GFX10-NEXT: v_mov_b32_e32 v1, 0
182-
; GFX10-NEXT: ds_write_b32 v2, v3 offset:65532
179+
; GFX10-NEXT: ds_write_b32 v3, v2
183180
; GFX10-NEXT: s_waitcnt lgkmcnt(0)
184181
; GFX10-NEXT: v_div_fmas_f32 v4, s0, s0, s0
185182
; GFX10-NEXT: global_store_dword v[0:1], v4, off
@@ -189,13 +186,11 @@ define amdgpu_kernel void @write_ds_sub_max_offset_global_clamp_bit(float %dummy
189186
; GFX11-LABEL: write_ds_sub_max_offset_global_clamp_bit:
190187
; GFX11: ; %bb.0:
191188
; GFX11-NEXT: s_load_b32 s0, s[0:1], 0x0
192-
; GFX11-NEXT: v_not_b32_e32 v0, v0
193189
; GFX11-NEXT: s_mov_b32 vcc_lo, 0
194-
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
195-
; GFX11-NEXT: v_dual_mov_b32 v3, 0x7b :: v_dual_lshlrev_b32 v2, 2, v0
196190
; GFX11-NEXT: v_mov_b32_e32 v0, 0
191+
; GFX11-NEXT: v_dual_mov_b32 v2, 0x7b :: v_dual_mov_b32 v3, 0
197192
; GFX11-NEXT: v_mov_b32_e32 v1, 0
198-
; GFX11-NEXT: ds_store_b32 v2, v3 offset:65532
193+
; GFX11-NEXT: ds_store_b32 v3, v2
199194
; GFX11-NEXT: s_waitcnt lgkmcnt(0)
200195
; GFX11-NEXT: v_div_fmas_f32 v4, s0, s0, s0
201196
; GFX11-NEXT: global_store_b32 v[0:1], v4, off dlc

llvm/test/Transforms/InstCombine/fold-log2-ceil-idiom.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ define i64 @log2_ceil_idiom_zext(i32 %x) {
4343
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X]], -1
4444
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false), !range [[RNG0]]
4545
; CHECK-NEXT: [[TMP3:%.*]] = sub nuw nsw i32 32, [[TMP2]]
46-
; CHECK-NEXT: [[RET:%.*]] = zext i32 [[TMP3]] to i64
46+
; CHECK-NEXT: [[RET:%.*]] = zext nneg i32 [[TMP3]] to i64
4747
; CHECK-NEXT: ret i64 [[RET]]
4848
;
4949
%ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)

llvm/test/Transforms/InstCombine/icmp-sub.ll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ define i1 @test_nuw_nsw_and_unsigned_pred(i64 %x) {
3636

3737
define i1 @test_nuw_nsw_and_signed_pred(i64 %x) {
3838
; CHECK-LABEL: @test_nuw_nsw_and_signed_pred(
39-
; CHECK-NEXT: [[Z:%.*]] = icmp sgt i64 [[X:%.*]], 7
39+
; CHECK-NEXT: [[Z:%.*]] = icmp ugt i64 [[X:%.*]], 7
4040
; CHECK-NEXT: ret i1 [[Z]]
4141
;
4242
%y = sub nuw nsw i64 10, %x
@@ -46,8 +46,7 @@ define i1 @test_nuw_nsw_and_signed_pred(i64 %x) {
4646

4747
define i1 @test_negative_nuw_and_signed_pred(i64 %x) {
4848
; CHECK-LABEL: @test_negative_nuw_and_signed_pred(
49-
; CHECK-NEXT: [[NOTSUB:%.*]] = add nuw i64 [[X:%.*]], -11
50-
; CHECK-NEXT: [[Z:%.*]] = icmp sgt i64 [[NOTSUB]], -4
49+
; CHECK-NEXT: [[Z:%.*]] = icmp ugt i64 [[X:%.*]], 7
5150
; CHECK-NEXT: ret i1 [[Z]]
5251
;
5352
%y = sub nuw i64 10, %x

llvm/test/Transforms/InstCombine/sub.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2367,7 +2367,7 @@ define <2 x i8> @sub_to_and_vector3(<2 x i8> %x) {
23672367
; CHECK-LABEL: @sub_to_and_vector3(
23682368
; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> <i8 71, i8 71>, [[X:%.*]]
23692369
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], <i8 120, i8 undef>
2370-
; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> <i8 44, i8 44>, [[AND]]
2370+
; CHECK-NEXT: [[R:%.*]] = sub nsw <2 x i8> <i8 44, i8 44>, [[AND]]
23712371
; CHECK-NEXT: ret <2 x i8> [[R]]
23722372
;
23732373
%sub = sub nuw <2 x i8> <i8 71, i8 71>, %x

llvm/unittests/Support/KnownBitsTest.cpp

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,41 +169,69 @@ static void TestAddSubExhaustive(bool IsAdd) {
169169
unsigned Bits = 4;
170170
ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
171171
ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
172-
KnownBits Known(Bits), KnownNSW(Bits);
172+
KnownBits Known(Bits), KnownNSW(Bits), KnownNUW(Bits),
173+
KnownNSWAndNUW(Bits);
173174
Known.Zero.setAllBits();
174175
Known.One.setAllBits();
175176
KnownNSW.Zero.setAllBits();
176177
KnownNSW.One.setAllBits();
178+
KnownNUW.Zero.setAllBits();
179+
KnownNUW.One.setAllBits();
180+
KnownNSWAndNUW.Zero.setAllBits();
181+
KnownNSWAndNUW.One.setAllBits();
177182

178183
ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
179184
ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
180-
bool Overflow;
185+
bool SignedOverflow;
186+
bool UnsignedOverflow;
181187
APInt Res;
182-
if (IsAdd)
183-
Res = N1.sadd_ov(N2, Overflow);
184-
else
185-
Res = N1.ssub_ov(N2, Overflow);
188+
if (IsAdd) {
189+
Res = N1.uadd_ov(N2, UnsignedOverflow);
190+
Res = N1.sadd_ov(N2, SignedOverflow);
191+
} else {
192+
Res = N1.usub_ov(N2, UnsignedOverflow);
193+
Res = N1.ssub_ov(N2, SignedOverflow);
194+
}
186195

187196
Known.One &= Res;
188197
Known.Zero &= ~Res;
189198

190-
if (!Overflow) {
199+
if (!SignedOverflow) {
191200
KnownNSW.One &= Res;
192201
KnownNSW.Zero &= ~Res;
193202
}
203+
204+
if (!UnsignedOverflow) {
205+
KnownNUW.One &= Res;
206+
KnownNUW.Zero &= ~Res;
207+
}
208+
209+
if (!UnsignedOverflow && !SignedOverflow) {
210+
KnownNSWAndNUW.One &= Res;
211+
KnownNSWAndNUW.Zero &= ~Res;
212+
}
194213
});
195214
});
196215

197216
KnownBits KnownComputed = KnownBits::computeForAddSub(
198217
IsAdd, /*NSW=*/false, /*NUW=*/false, Known1, Known2);
199-
EXPECT_EQ(Known, KnownComputed);
218+
EXPECT_TRUE(isOptimal(Known, KnownComputed, {Known1, Known2}));
200219

201-
// The NSW calculation is not precise, only check that it's
202-
// conservatively correct.
203220
KnownBits KnownNSWComputed = KnownBits::computeForAddSub(
204221
IsAdd, /*NSW=*/true, /*NUW=*/false, Known1, Known2);
205-
EXPECT_TRUE(KnownNSWComputed.Zero.isSubsetOf(KnownNSW.Zero));
206-
EXPECT_TRUE(KnownNSWComputed.One.isSubsetOf(KnownNSW.One));
222+
if (!KnownNSW.hasConflict())
223+
EXPECT_TRUE(isOptimal(KnownNSW, KnownNSWComputed, {Known1, Known2}));
224+
225+
KnownBits KnownNUWComputed = KnownBits::computeForAddSub(
226+
IsAdd, /*NSW=*/false, /*NUW=*/true, Known1, Known2);
227+
if (!KnownNUW.hasConflict())
228+
EXPECT_TRUE(isOptimal(KnownNUW, KnownNUWComputed, {Known1, Known2}));
229+
230+
KnownBits KnownNSWAndNUWComputed = KnownBits::computeForAddSub(
231+
IsAdd, /*NSW=*/true, /*NUW=*/true, Known1, Known2);
232+
if (!KnownNSWAndNUW.hasConflict())
233+
EXPECT_TRUE(isOptimal(KnownNSWAndNUW, KnownNSWAndNUWComputed,
234+
{Known1, Known2}));
207235
});
208236
});
209237
}
@@ -244,6 +272,28 @@ TEST(KnownBitsTest, SubBorrowExhaustive) {
244272
});
245273
}
246274

275+
TEST(KnownBitsTest, SignBitUnknown) {
276+
KnownBits Known(2);
277+
EXPECT_TRUE(Known.isSignUnknown());
278+
Known.Zero.setBit(0);
279+
EXPECT_TRUE(Known.isSignUnknown());
280+
Known.Zero.setBit(1);
281+
EXPECT_FALSE(Known.isSignUnknown());
282+
Known.Zero.clearBit(0);
283+
EXPECT_FALSE(Known.isSignUnknown());
284+
Known.Zero.clearBit(1);
285+
EXPECT_TRUE(Known.isSignUnknown());
286+
287+
Known.One.setBit(0);
288+
EXPECT_TRUE(Known.isSignUnknown());
289+
Known.One.setBit(1);
290+
EXPECT_FALSE(Known.isSignUnknown());
291+
Known.One.clearBit(0);
292+
EXPECT_FALSE(Known.isSignUnknown());
293+
Known.One.clearBit(1);
294+
EXPECT_TRUE(Known.isSignUnknown());
295+
}
296+
247297
TEST(KnownBitsTest, AbsDiffSpecialCase) {
248298
// There are 2 implementation of absdiff - both are currently needed to cover
249299
// extra cases.

0 commit comments

Comments
 (0)