Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ LLVM_ABI void computeKnownBitsFromContext(const Value *V, KnownBits &Known,
const SimplifyQuery &Q,
unsigned Depth = 0);

/// Update \p Known with bits of \p V that are implied by \p Cmp.
/// Comparisons involving `trunc V` are handled specially: known
/// bits are computed for the truncated value and then extended to the bitwidth
/// of \p V.
LLVM_ABI void computeKnownBitsFromICmpCond(const Value *V, ICmpInst *Cmp,
KnownBits &Known,
const SimplifyQuery &SQ,
bool Invert);

/// Using KnownBits LHS/RHS produce the known bits for logic op (and/xor/or).
LLVM_ABI KnownBits analyzeKnownBitsFromAndXorOr(const Operator *I,
const KnownBits &KnownLHS,
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -968,9 +968,9 @@ static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
}
}

static void computeKnownBitsFromICmpCond(const Value *V, ICmpInst *Cmp,
KnownBits &Known,
const SimplifyQuery &SQ, bool Invert) {
void llvm::computeKnownBitsFromICmpCond(const Value *V, ICmpInst *Cmp,
KnownBits &Known,
const SimplifyQuery &SQ, bool Invert) {
ICmpInst::Predicate Pred =
Invert ? Cmp->getInversePredicate() : Cmp->getPredicate();
Value *LHS = Cmp->getOperand(0);
Expand Down
37 changes: 37 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
#include "llvm/Analysis/CmpInstAnalysis.h"
#include "llvm/Analysis/FloatingPointPredicateUtils.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Transforms/InstCombine/InstCombiner.h"
#include "llvm/Transforms/Utils/Local.h"

Expand Down Expand Up @@ -3575,6 +3577,41 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
return Builder.createIsFPClass(X, IsAnd ? FPClassTest::fcNormal
: ~FPClassTest::fcNormal);

if (!IsLogical && IsAnd) {
auto TryCandidate = [&](Value *X) -> Value * {
if (!X->getType()->isIntegerTy())
return nullptr;

Type *Ty = X->getType();
unsigned BitWidth = Ty->getScalarSizeInBits();

// KnownL and KnownR hold information deduced from the LHS icmp and RHS
// icmps, respectively
KnownBits KnownL(BitWidth), KnownR(BitWidth);

computeKnownBitsFromICmpCond(X, LHS, KnownL, Q, /*Invert=*/false);
computeKnownBitsFromICmpCond(X, RHS, KnownR, Q, /*Invert=*/false);

KnownBits Combined = KnownL.unionWith(KnownR);

// Avoid stomping on cases where one icmp alone determines X. Those are
// handled by more specific InstCombine folds.
if (KnownL.isConstant() || KnownR.isConstant())
return nullptr;

if (!Combined.isConstant())
return nullptr;

APInt ConstVal = Combined.getConstant();
return Builder.CreateICmpEQ(X, ConstantInt::get(Ty, ConstVal));
};
Comment on lines +3581 to +3607
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part fine as a lambda, or should it be its own helper function? If it should be its own helper function, then what should it be called?


if (Value *Res = TryCandidate(LHS0))
return Res;
if (Value *Res = TryCandidate(RHS0))
return Res;
}

return foldAndOrOfICmpsUsingRanges(LHS, RHS, IsAnd);
}

Expand Down
43 changes: 34 additions & 9 deletions llvm/test/Transforms/InstCombine/and-or-icmps.ll
Original file line number Diff line number Diff line change
Expand Up @@ -702,9 +702,9 @@ define i1 @PR42691_10_logical(i32 %x) {

define i1 @substitute_constant_and_eq_eq(i8 %x, i8 %y) {
; CHECK-LABEL: @substitute_constant_and_eq_eq(
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X:%.*]], 42
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[R:%.*]] = and i1 [[C1]], [[TMP1]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[Y1:%.*]], 42
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%c1 = icmp eq i8 %x, 42
Expand All @@ -728,9 +728,9 @@ define i1 @substitute_constant_and_eq_eq_logical(i8 %x, i8 %y) {

define i1 @substitute_constant_and_eq_eq_commute(i8 %x, i8 %y) {
; CHECK-LABEL: @substitute_constant_and_eq_eq_commute(
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X:%.*]], 42
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[R:%.*]] = and i1 [[C1]], [[TMP1]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[Y1:%.*]], 42
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%c1 = icmp eq i8 %x, 42
Expand All @@ -741,9 +741,9 @@ define i1 @substitute_constant_and_eq_eq_commute(i8 %x, i8 %y) {

define i1 @substitute_constant_and_eq_eq_commute_logical(i8 %x, i8 %y) {
; CHECK-LABEL: @substitute_constant_and_eq_eq_commute_logical(
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[X:%.*]], 42
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[R:%.*]] = and i1 [[C1]], [[TMP1]]
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[Y1:%.*]], 42
; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%c1 = icmp eq i8 %x, 42
Expand Down Expand Up @@ -1392,12 +1392,12 @@ define i1 @bitwise_and_bitwise_and_icmps(i8 %x, i8 %y, i8 %z) {

define i1 @bitwise_and_bitwise_and_icmps_comm1(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @bitwise_and_bitwise_and_icmps_comm1(
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[Z_SHIFT:%.*]] = shl nuw i8 1, [[Z:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[Z_SHIFT]], 1
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[C1]], [[TMP3]]
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[TMP3]], [[TMP4]]
; CHECK-NEXT: ret i1 [[AND2]]
;
%c1 = icmp eq i8 %y, 42
Expand Down Expand Up @@ -3721,3 +3721,28 @@ define i1 @merge_range_check_or(i8 %a) {
%and = or i1 %cmp1, %cmp2
ret i1 %and
}

; Just a very complicated way of checking if v1 == 0.
define i1 @complicated_zero_equality_test(i64 %v1) {
; CHECK-LABEL: @complicated_zero_equality_test(
; CHECK-NEXT: [[V5:%.*]] = icmp eq i64 [[V1:%.*]], 0
; CHECK-NEXT: ret i1 [[V5]]
;
%v2 = trunc i64 %v1 to i32
%v3 = icmp eq i32 %v2, 0
%v4 = icmp ult i64 %v1, 4294967296 ; 2 ^ 32
%v5 = and i1 %v4, %v3
ret i1 %v5
}

define i1 @commuted_complicated_zero_equality_test(i64 %v1) {
; CHECK-LABEL: @commuted_complicated_zero_equality_test(
; CHECK-NEXT: [[V5:%.*]] = icmp eq i64 [[V1:%.*]], 0
; CHECK-NEXT: ret i1 [[V5]]
;
%v2 = trunc i64 %v1 to i32
%v3 = icmp ult i64 %v1, 4294967296 ; 2 ^ 32
%v4 = icmp eq i32 %v2, 0
%v5 = and i1 %v4, %v3
ret i1 %v5
}
Loading