mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[LVI][CVP] Handle (x | y) < C style conditions
InstCombine may convert conditions like (x < C) && (y < C) into (x | y) < C (for some C). This patch teaches LVI to recognize that in this case, it can infer either x < C or y < C along the edge. This fixes the issue reported at https://github.com/rust-lang/rust/issues/73827. Differential Revision: https://reviews.llvm.org/D82715
This commit is contained in:
parent
18ec6d20cc
commit
ef280239b6
@ -1093,7 +1093,8 @@ Optional<ValueLatticeElement> LazyValueInfoImpl::solveBlockValueExtractValue(
|
|||||||
return ValueLatticeElement::getOverdefined();
|
return ValueLatticeElement::getOverdefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool matchICmpOperand(const APInt *&Offset, Value *LHS, Value *Val) {
|
static bool matchICmpOperand(const APInt *&Offset, Value *LHS, Value *Val,
|
||||||
|
ICmpInst::Predicate Pred) {
|
||||||
if (LHS == Val)
|
if (LHS == Val)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -1102,6 +1103,16 @@ static bool matchICmpOperand(const APInt *&Offset, Value *LHS, Value *Val) {
|
|||||||
if (match(LHS, m_Add(m_Specific(Val), m_APInt(Offset))))
|
if (match(LHS, m_Add(m_Specific(Val), m_APInt(Offset))))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// If (x | y) < C, then (x < C) && (y < C).
|
||||||
|
if (match(LHS, m_c_Or(m_Specific(Val), m_Value())) &&
|
||||||
|
(Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If (x & y) > C, then (x > C) && (y > C).
|
||||||
|
if (match(LHS, m_c_And(m_Specific(Val), m_Value())) &&
|
||||||
|
(Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,10 +1138,10 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
|
|||||||
return ValueLatticeElement::getOverdefined();
|
return ValueLatticeElement::getOverdefined();
|
||||||
|
|
||||||
const APInt *Offset = nullptr;
|
const APInt *Offset = nullptr;
|
||||||
if (!matchICmpOperand(Offset, LHS, Val)) {
|
if (!matchICmpOperand(Offset, LHS, Val, EdgePred)) {
|
||||||
std::swap(LHS, RHS);
|
std::swap(LHS, RHS);
|
||||||
EdgePred = CmpInst::getSwappedPredicate(EdgePred);
|
EdgePred = CmpInst::getSwappedPredicate(EdgePred);
|
||||||
if (!matchICmpOperand(Offset, LHS, Val))
|
if (!matchICmpOperand(Offset, LHS, Val, EdgePred))
|
||||||
return ValueLatticeElement::getOverdefined();
|
return ValueLatticeElement::getOverdefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,10 +659,8 @@ define void @test_icmp_or_ult(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[OR]], 42
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[OR]], 42
|
||||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
||||||
; CHECK: if.true:
|
; CHECK: if.true:
|
||||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP2]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp uge i32 [[A]], 42
|
; CHECK-NEXT: [[CMP4:%.*]] = icmp uge i32 [[A]], 42
|
||||||
@ -698,10 +696,8 @@ define void @test_icmp_or_ule(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[OR]], 42
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[OR]], 42
|
||||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
||||||
; CHECK: if.true:
|
; CHECK: if.true:
|
||||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP2]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ule i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp ugt i32 [[A]], 42
|
; CHECK-NEXT: [[CMP4:%.*]] = icmp ugt i32 [[A]], 42
|
||||||
@ -743,10 +739,8 @@ define void @test_icmp_or_ugt(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp ule i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP4]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP5:%.*]] = icmp ule i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP5]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
@ -782,10 +776,8 @@ define void @test_icmp_or_uge(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP4]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP5:%.*]] = icmp ult i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP5]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
@ -854,10 +846,8 @@ define void @test_icmp_and_ugt(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[AND]], 42
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[AND]], 42
|
||||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
||||||
; CHECK: if.true:
|
; CHECK: if.true:
|
||||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP2]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp ule i32 [[A]], 42
|
; CHECK-NEXT: [[CMP4:%.*]] = icmp ule i32 [[A]], 42
|
||||||
@ -893,10 +883,8 @@ define void @test_icmp_and_uge(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[AND]], 42
|
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[AND]], 42
|
||||||
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
; CHECK-NEXT: br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
||||||
; CHECK: if.true:
|
; CHECK: if.true:
|
||||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp uge i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP2]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP3:%.*]] = icmp uge i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 42
|
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 42
|
||||||
@ -938,10 +926,8 @@ define void @test_icmp_and_ult(i32 %a, i32 %b) {
|
|||||||
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
; CHECK-NEXT: call void @check1(i1 [[CMP3]])
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
; CHECK: if.false:
|
; CHECK: if.false:
|
||||||
; CHECK-NEXT: [[CMP4:%.*]] = icmp uge i32 [[A]], 42
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP4]])
|
; CHECK-NEXT: call void @check1(i1 true)
|
||||||
; CHECK-NEXT: [[CMP5:%.*]] = icmp uge i32 [[B]], 42
|
|
||||||
; CHECK-NEXT: call void @check1(i1 [[CMP5]])
|
|
||||||
; CHECK-NEXT: ret void
|
; CHECK-NEXT: ret void
|
||||||
;
|
;
|
||||||
entry:
|
entry:
|
||||||
|
Loading…
Reference in New Issue
Block a user