Skip to content

Commit ffcff4a

Browse files
authored
[ValueTracking] Infer is-power-of-2 from assumptions. (#107745)
This patch tries to infer is-power-of-2 from assumptions. I don't see that this kind of assumption exists in my dataset. Related issue: rust-lang/rust#129795 Close #58996.
1 parent eb0e4b1 commit ffcff4a

File tree

4 files changed

+128
-3
lines changed

4 files changed

+128
-3
lines changed

llvm/lib/Analysis/ValueTracking.cpp

+36-3
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
613613
CmpInst::Predicate Pred;
614614
auto m_V = m_CombineOr(m_Specific(V), m_PtrToInt(m_Specific(V)));
615615
if (!match(I->getArgOperand(0), m_c_ICmp(Pred, m_V, m_Value(RHS))))
616-
return false;
616+
continue;
617617

618618
if (cmpExcludesZero(Pred, RHS) && isValidAssumeForContext(I, Q.CxtI, Q.DT))
619619
return true;
@@ -2207,6 +2207,22 @@ static bool isPowerOfTwoRecurrence(const PHINode *PN, bool OrZero,
22072207
}
22082208
}
22092209

2210+
/// Return true if we can infer that \p V is known to be a power of 2 from
2211+
/// dominating condition \p Cond (e.g., ctpop(V) == 1).
2212+
static bool isImpliedToBeAPowerOfTwoFromCond(const Value *V, bool OrZero,
2213+
const Value *Cond) {
2214+
ICmpInst::Predicate Pred;
2215+
const APInt *RHSC;
2216+
if (!match(Cond, m_ICmp(Pred, m_Intrinsic<Intrinsic::ctpop>(m_Specific(V)),
2217+
m_APInt(RHSC))))
2218+
return false;
2219+
// ctpop(V) u< 2
2220+
if (OrZero && Pred == ICmpInst::ICMP_ULT && *RHSC == 2)
2221+
return true;
2222+
// ctpop(V) == 1
2223+
return Pred == ICmpInst::ICMP_EQ && *RHSC == 1;
2224+
}
2225+
22102226
/// Return true if the given value is known to have exactly one
22112227
/// bit set when defined. For vectors return true if every element is known to
22122228
/// be a power of two when defined. Supports values with integer or pointer
@@ -2222,6 +2238,18 @@ bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
22222238
if (OrZero && V->getType()->getScalarSizeInBits() == 1)
22232239
return true;
22242240

2241+
// Try to infer from assumptions.
2242+
if (Q.AC && Q.CxtI) {
2243+
for (auto &AssumeVH : Q.AC->assumptionsFor(V)) {
2244+
if (!AssumeVH)
2245+
continue;
2246+
CallInst *I = cast<CallInst>(AssumeVH);
2247+
if (isImpliedToBeAPowerOfTwoFromCond(V, OrZero, I->getArgOperand(0)) &&
2248+
isValidAssumeForContext(I, Q.CxtI, Q.DT))
2249+
return true;
2250+
}
2251+
}
2252+
22252253
auto *I = dyn_cast<Instruction>(V);
22262254
if (!I)
22272255
return false;
@@ -9903,8 +9931,9 @@ void llvm::findValuesAffectedByCondition(
99039931
} else if (match(V, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
99049932
AddCmpOperands(A, B);
99059933

9934+
bool HasRHSC = match(B, m_ConstantInt());
99069935
if (ICmpInst::isEquality(Pred)) {
9907-
if (match(B, m_ConstantInt())) {
9936+
if (HasRHSC) {
99089937
Value *Y;
99099938
// (X & C) or (X | C) or (X ^ C).
99109939
// (X << C) or (X >>_s C) or (X >>_u C).
@@ -9918,7 +9947,7 @@ void llvm::findValuesAffectedByCondition(
99189947
}
99199948
}
99209949
} else {
9921-
if (match(B, m_ConstantInt())) {
9950+
if (HasRHSC) {
99229951
// Handle (A + C1) u< C2, which is the canonical form of
99239952
// A > C3 && A < C4.
99249953
if (match(A, m_AddLike(m_Value(X), m_ConstantInt())))
@@ -9950,6 +9979,10 @@ void llvm::findValuesAffectedByCondition(
99509979
InsertAffected(X);
99519980
}
99529981
}
9982+
9983+
if (IsAssume && HasRHSC &&
9984+
match(A, m_Intrinsic<Intrinsic::ctpop>(m_Value(X))))
9985+
AddAffected(X);
99539986
} else if (match(Cond, m_FCmp(Pred, m_Value(A), m_Value(B)))) {
99549987
AddCmpOperands(A, B);
99559988

llvm/test/Transforms/InstCombine/cttz.ll

+21
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,24 @@ define i32 @cttz_of_power_of_two_wrong_constant_2(i32 %x) {
276276
%r = call i32 @llvm.cttz.i32(i32 %add, i1 false)
277277
ret i32 %r
278278
}
279+
280+
define i16 @cttz_assume(i16 %x) {
281+
; CHECK-LABEL: @cttz_assume(
282+
; CHECK-NEXT: [[ADD:%.*]] = add i16 [[X:%.*]], 1
283+
; CHECK-NEXT: [[COND0:%.*]] = icmp ult i16 [[ADD]], 10
284+
; CHECK-NEXT: call void @llvm.assume(i1 [[COND0]])
285+
; CHECK-NEXT: [[COND1:%.*]] = icmp ne i16 [[X]], 0
286+
; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
287+
; CHECK-NEXT: [[CTTZ:%.*]] = call range(i16 0, 17) i16 @llvm.cttz.i16(i16 [[X]], i1 true)
288+
; CHECK-NEXT: ret i16 [[CTTZ]]
289+
;
290+
%add = add i16 %x, 1
291+
%cond0 = icmp ult i16 %add, 10
292+
call void @llvm.assume(i1 %cond0)
293+
294+
%cond1 = icmp ne i16 %x, 0
295+
call void @llvm.assume(i1 %cond1)
296+
297+
%cttz = call i16 @llvm.cttz.i16(i16 %x, i1 false)
298+
ret i16 %cttz
299+
}

llvm/test/Transforms/InstCombine/icmp.ll

+39
Original file line numberDiff line numberDiff line change
@@ -5326,3 +5326,42 @@ define i1 @pr94897(i32 range(i32 -2147483648, 0) %x) {
53265326
%cmp = icmp ugt i32 %shl, -50331648
53275327
ret i1 %cmp
53285328
}
5329+
5330+
define i1 @icmp_and_inv_pow2_ne_0(i32 %A, i32 %B) {
5331+
; CHECK-LABEL: @icmp_and_inv_pow2_ne_0(
5332+
; CHECK-NEXT: [[POPCNT:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[A:%.*]])
5333+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[POPCNT]], 1
5334+
; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
5335+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B:%.*]]
5336+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
5337+
; CHECK-NEXT: ret i1 [[CMP]]
5338+
;
5339+
%popcnt = tail call i32 @llvm.ctpop.i32(i32 %A)
5340+
%cond = icmp eq i32 %popcnt, 1
5341+
call void @llvm.assume(i1 %cond)
5342+
5343+
%inv = xor i32 %B, -1
5344+
%and = and i32 %A, %inv
5345+
%cmp = icmp ne i32 %and, 0
5346+
ret i1 %cmp
5347+
}
5348+
5349+
define i1 @icmp_and_inv_pow2_or_zero_ne_0(i32 %A, i32 %B) {
5350+
; CHECK-LABEL: @icmp_and_inv_pow2_or_zero_ne_0(
5351+
; CHECK-NEXT: [[POPCNT:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[A:%.*]])
5352+
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[POPCNT]], 2
5353+
; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
5354+
; CHECK-NEXT: [[INV:%.*]] = xor i32 [[B:%.*]], -1
5355+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[A]], [[INV]]
5356+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0
5357+
; CHECK-NEXT: ret i1 [[CMP]]
5358+
;
5359+
%popcnt = tail call i32 @llvm.ctpop.i32(i32 %A)
5360+
%cond = icmp ult i32 %popcnt, 2
5361+
call void @llvm.assume(i1 %cond)
5362+
5363+
%inv = xor i32 %B, -1
5364+
%and = and i32 %A, %inv
5365+
%cmp = icmp ne i32 %and, 0
5366+
ret i1 %cmp
5367+
}

llvm/test/Transforms/InstCombine/rem.ll

+32
Original file line numberDiff line numberDiff line change
@@ -1041,3 +1041,35 @@ define <2 x i32> @PR62401(<2 x i1> %x, <2 x i32> %y) {
10411041
%r = urem <2 x i32> %y, %sext.i1
10421042
ret <2 x i32> %r
10431043
}
1044+
1045+
define i16 @rem_pow2_or_zero(i16 %x, i16 %y) {
1046+
; CHECK-LABEL: @rem_pow2_or_zero(
1047+
; CHECK-NEXT: [[POPCNT:%.*]] = call range(i16 1, 17) i16 @llvm.ctpop.i16(i16 [[Y:%.*]])
1048+
; CHECK-NEXT: [[COND:%.*]] = icmp ult i16 [[POPCNT]], 2
1049+
; CHECK-NEXT: tail call void @llvm.assume(i1 [[COND]])
1050+
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[Y]], -1
1051+
; CHECK-NEXT: [[REM:%.*]] = and i16 [[X:%.*]], [[TMP1]]
1052+
; CHECK-NEXT: ret i16 [[REM]]
1053+
;
1054+
%popcnt = call i16 @llvm.ctpop.i16(i16 %y)
1055+
%cond = icmp ult i16 %popcnt, 2
1056+
tail call void @llvm.assume(i1 %cond)
1057+
%rem = urem i16 %x, %y
1058+
ret i16 %rem
1059+
}
1060+
1061+
define i16 @rem_pow2(i16 %x, i16 %y) {
1062+
; CHECK-LABEL: @rem_pow2(
1063+
; CHECK-NEXT: [[POPCNT:%.*]] = call range(i16 1, 17) i16 @llvm.ctpop.i16(i16 [[Y:%.*]])
1064+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i16 [[POPCNT]], 1
1065+
; CHECK-NEXT: tail call void @llvm.assume(i1 [[COND]])
1066+
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[Y]], -1
1067+
; CHECK-NEXT: [[REM:%.*]] = and i16 [[X:%.*]], [[TMP1]]
1068+
; CHECK-NEXT: ret i16 [[REM]]
1069+
;
1070+
%popcnt = call i16 @llvm.ctpop.i16(i16 %y)
1071+
%cond = icmp eq i16 %popcnt, 1
1072+
tail call void @llvm.assume(i1 %cond)
1073+
%rem = urem i16 %x, %y
1074+
ret i16 %rem
1075+
}

0 commit comments

Comments
 (0)