Skip to content

Commit 2ca75df

Browse files
authored
[ValueTracking] Infer is-power-of-2 from dominating conditions (#107994)
Addresses downstream rustc issue: rust-lang/rust#129795
1 parent 13280d9 commit 2ca75df

File tree

4 files changed

+136
-10
lines changed

4 files changed

+136
-10
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

+3
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ bool isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL,
119119
const DominatorTree *DT = nullptr,
120120
bool UseInstrInfo = true);
121121

122+
bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
123+
const SimplifyQuery &Q);
124+
122125
bool isOnlyUsedInZeroComparison(const Instruction *CxtI);
123126

124127
bool isOnlyUsedInZeroEqualityComparison(const Instruction *CxtI);

llvm/include/llvm/Transforms/InstCombine/InstCombiner.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
450450
bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero = false,
451451
unsigned Depth = 0,
452452
const Instruction *CxtI = nullptr) {
453-
return llvm::isKnownToBeAPowerOfTwo(V, DL, OrZero, Depth, &AC, CxtI, &DT);
453+
return llvm::isKnownToBeAPowerOfTwo(V, OrZero, Depth,
454+
SQ.getWithInstruction(CxtI));
454455
}
455456

456457
bool MaskedValueIsZero(const Value *V, const APInt &Mask, unsigned Depth = 0,

llvm/lib/Analysis/ValueTracking.cpp

+28-9
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,6 @@ bool llvm::isOnlyUsedInZeroEqualityComparison(const Instruction *I) {
265265
});
266266
}
267267

268-
static bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
269-
const SimplifyQuery &Q);
270-
271268
bool llvm::isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL,
272269
bool OrZero, unsigned Depth,
273270
AssumptionCache *AC, const Instruction *CxtI,
@@ -2210,12 +2207,15 @@ static bool isPowerOfTwoRecurrence(const PHINode *PN, bool OrZero,
22102207
/// Return true if we can infer that \p V is known to be a power of 2 from
22112208
/// dominating condition \p Cond (e.g., ctpop(V) == 1).
22122209
static bool isImpliedToBeAPowerOfTwoFromCond(const Value *V, bool OrZero,
2213-
const Value *Cond) {
2210+
const Value *Cond,
2211+
bool CondIsTrue) {
22142212
ICmpInst::Predicate Pred;
22152213
const APInt *RHSC;
22162214
if (!match(Cond, m_ICmp(Pred, m_Intrinsic<Intrinsic::ctpop>(m_Specific(V)),
22172215
m_APInt(RHSC))))
22182216
return false;
2217+
if (!CondIsTrue)
2218+
Pred = ICmpInst::getInversePredicate(Pred);
22192219
// ctpop(V) u< 2
22202220
if (OrZero && Pred == ICmpInst::ICMP_ULT && *RHSC == 2)
22212221
return true;
@@ -2227,8 +2227,8 @@ static bool isImpliedToBeAPowerOfTwoFromCond(const Value *V, bool OrZero,
22272227
/// bit set when defined. For vectors return true if every element is known to
22282228
/// be a power of two when defined. Supports values with integer or pointer
22292229
/// types and vectors of integers.
2230-
bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
2231-
const SimplifyQuery &Q) {
2230+
bool llvm::isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
2231+
const SimplifyQuery &Q) {
22322232
assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
22332233

22342234
if (isa<Constant>(V))
@@ -2244,12 +2244,32 @@ bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
22442244
if (!AssumeVH)
22452245
continue;
22462246
CallInst *I = cast<CallInst>(AssumeVH);
2247-
if (isImpliedToBeAPowerOfTwoFromCond(V, OrZero, I->getArgOperand(0)) &&
2247+
if (isImpliedToBeAPowerOfTwoFromCond(V, OrZero, I->getArgOperand(0),
2248+
/*CondIsTrue=*/true) &&
22482249
isValidAssumeForContext(I, Q.CxtI, Q.DT))
22492250
return true;
22502251
}
22512252
}
22522253

2254+
// Handle dominating conditions.
2255+
if (Q.DC && Q.CxtI && Q.DT) {
2256+
for (BranchInst *BI : Q.DC->conditionsFor(V)) {
2257+
Value *Cond = BI->getCondition();
2258+
2259+
BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0));
2260+
if (isImpliedToBeAPowerOfTwoFromCond(V, OrZero, Cond,
2261+
/*CondIsTrue=*/true) &&
2262+
Q.DT->dominates(Edge0, Q.CxtI->getParent()))
2263+
return true;
2264+
2265+
BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1));
2266+
if (isImpliedToBeAPowerOfTwoFromCond(V, OrZero, Cond,
2267+
/*CondIsTrue=*/false) &&
2268+
Q.DT->dominates(Edge1, Q.CxtI->getParent()))
2269+
return true;
2270+
}
2271+
}
2272+
22532273
auto *I = dyn_cast<Instruction>(V);
22542274
if (!I)
22552275
return false;
@@ -9980,8 +10000,7 @@ void llvm::findValuesAffectedByCondition(
998010000
}
998110001
}
998210002

9983-
if (IsAssume && HasRHSC &&
9984-
match(A, m_Intrinsic<Intrinsic::ctpop>(m_Value(X))))
10003+
if (HasRHSC && match(A, m_Intrinsic<Intrinsic::ctpop>(m_Value(X))))
998510004
AddAffected(X);
998610005
} else if (match(Cond, m_FCmp(Pred, m_Value(A), m_Value(B)))) {
998710006
AddCmpOperands(A, B);

llvm/test/Transforms/InstCombine/rem.ll

+103
Original file line numberDiff line numberDiff line change
@@ -1073,3 +1073,106 @@ define i16 @rem_pow2(i16 %x, i16 %y) {
10731073
%rem = urem i16 %x, %y
10741074
ret i16 %rem
10751075
}
1076+
1077+
define i64 @rem_pow2_domcond(i64 %a, i64 %b) {
1078+
; CHECK-LABEL: @rem_pow2_domcond(
1079+
; CHECK-NEXT: start:
1080+
; CHECK-NEXT: [[CPOP:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[B:%.*]])
1081+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[CPOP]], 1
1082+
; CHECK-NEXT: br i1 [[COND]], label [[BB1:%.*]], label [[BB2:%.*]]
1083+
; CHECK: bb1:
1084+
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[B]], -1
1085+
; CHECK-NEXT: [[REM:%.*]] = and i64 [[A:%.*]], [[TMP0]]
1086+
; CHECK-NEXT: ret i64 [[REM]]
1087+
; CHECK: bb2:
1088+
; CHECK-NEXT: ret i64 0
1089+
;
1090+
start:
1091+
%cpop = call i64 @llvm.ctpop.i64(i64 %b)
1092+
%cond = icmp eq i64 %cpop, 1
1093+
br i1 %cond, label %bb1, label %bb2
1094+
1095+
bb1:
1096+
%rem = urem i64 %a, %b
1097+
ret i64 %rem
1098+
1099+
bb2:
1100+
ret i64 0
1101+
}
1102+
1103+
define i64 @rem_pow2_domcond_in_else(i64 %a, i64 %b) {
1104+
; CHECK-LABEL: @rem_pow2_domcond_in_else(
1105+
; CHECK-NEXT: start:
1106+
; CHECK-NEXT: [[CPOP:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[B:%.*]])
1107+
; CHECK-NEXT: [[COND_NOT:%.*]] = icmp eq i64 [[CPOP]], 1
1108+
; CHECK-NEXT: br i1 [[COND_NOT]], label [[BB1:%.*]], label [[BB2:%.*]]
1109+
; CHECK: bb1:
1110+
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[B]], -1
1111+
; CHECK-NEXT: [[REM:%.*]] = and i64 [[A:%.*]], [[TMP0]]
1112+
; CHECK-NEXT: ret i64 [[REM]]
1113+
; CHECK: bb2:
1114+
; CHECK-NEXT: ret i64 0
1115+
;
1116+
start:
1117+
%cpop = call i64 @llvm.ctpop.i64(i64 %b)
1118+
%cond = icmp ne i64 %cpop, 1
1119+
br i1 %cond, label %bb2, label %bb1
1120+
1121+
bb1:
1122+
%rem = urem i64 %a, %b
1123+
ret i64 %rem
1124+
1125+
bb2:
1126+
ret i64 0
1127+
}
1128+
1129+
define i64 @rem_pow2_or_zero_domcond(i64 %a, i64 %b) {
1130+
; CHECK-LABEL: @rem_pow2_or_zero_domcond(
1131+
; CHECK-NEXT: start:
1132+
; CHECK-NEXT: [[CPOP:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[B:%.*]])
1133+
; CHECK-NEXT: [[COND:%.*]] = icmp ult i64 [[CPOP]], 2
1134+
; CHECK-NEXT: br i1 [[COND]], label [[BB1:%.*]], label [[BB2:%.*]]
1135+
; CHECK: bb1:
1136+
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[B]], -1
1137+
; CHECK-NEXT: [[REM:%.*]] = and i64 [[A:%.*]], [[TMP0]]
1138+
; CHECK-NEXT: ret i64 [[REM]]
1139+
; CHECK: bb2:
1140+
; CHECK-NEXT: ret i64 0
1141+
;
1142+
start:
1143+
%cpop = call i64 @llvm.ctpop.i64(i64 %b)
1144+
%cond = icmp ult i64 %cpop, 2
1145+
br i1 %cond, label %bb1, label %bb2
1146+
1147+
bb1:
1148+
%rem = urem i64 %a, %b
1149+
ret i64 %rem
1150+
1151+
bb2:
1152+
ret i64 0
1153+
}
1154+
1155+
define i64 @rem_pow2_non_domcond(i64 %a, i64 %b) {
1156+
; CHECK-LABEL: @rem_pow2_non_domcond(
1157+
; CHECK-NEXT: start:
1158+
; CHECK-NEXT: [[CPOP:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[B:%.*]])
1159+
; CHECK-NEXT: [[COND_NOT:%.*]] = icmp eq i64 [[CPOP]], 1
1160+
; CHECK-NEXT: br i1 [[COND_NOT]], label [[BB1:%.*]], label [[BB2:%.*]]
1161+
; CHECK: bb1:
1162+
; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B]]
1163+
; CHECK-NEXT: ret i64 [[REM]]
1164+
; CHECK: bb2:
1165+
; CHECK-NEXT: br label [[BB1]]
1166+
;
1167+
start:
1168+
%cpop = call i64 @llvm.ctpop.i64(i64 %b)
1169+
%cond = icmp ne i64 %cpop, 1
1170+
br i1 %cond, label %bb2, label %bb1
1171+
1172+
bb1:
1173+
%rem = urem i64 %a, %b
1174+
ret i64 %rem
1175+
1176+
bb2:
1177+
br label %bb1
1178+
}

0 commit comments

Comments
 (0)