From b590ade35e7154527e78af6354eb351fbae8467d Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Thu, 19 May 2016 03:53:17 +0000 Subject: [PATCH] [GuardWidening] Use getEquivalentICmp to fold constant compares `ConstantRange::getEquivalentICmp` is more general, and better factored. llvm-svn: 270019 --- lib/Transforms/Scalar/GuardWidening.cpp | 34 +++++++++++------- test/Transforms/GuardWidening/basic.ll | 46 ++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/lib/Transforms/Scalar/GuardWidening.cpp b/lib/Transforms/Scalar/GuardWidening.cpp index d0bd614533d..5ac4374038e 100644 --- a/lib/Transforms/Scalar/GuardWidening.cpp +++ b/lib/Transforms/Scalar/GuardWidening.cpp @@ -356,21 +356,31 @@ bool GuardWideningImpl::widenCondCommon(Value *Cond0, Value *Cond1, if (match(Cond0, m_ICmp(Pred0, m_Value(LHS), m_ConstantInt(RHS0))) && match(Cond1, m_ICmp(Pred1, m_Specific(LHS), m_ConstantInt(RHS1)))) { - // TODO: This logic should be generalized and refactored into a new - // Constant::getEquivalentICmp helper. - if (Pred0 == ICmpInst::ICMP_NE && RHS0->isZero()) - Pred0 = ICmpInst::ICMP_UGT; - if (Pred1 == ICmpInst::ICMP_NE && RHS1->isZero()) - Pred1 = ICmpInst::ICMP_UGT; + ConstantRange CR0 = + ConstantRange::makeExactICmpRegion(Pred0, RHS0->getValue()); + ConstantRange CR1 = + ConstantRange::makeExactICmpRegion(Pred1, RHS1->getValue()); - if (Pred0 == ICmpInst::ICMP_UGT && Pred1 == ICmpInst::ICMP_UGT) { + // SubsetIntersect is a subset of the actual mathematical intersection of + // CR0 and CR1, while SupersetIntersect is a superset of the the actual + // mathematical intersection. If these two ConstantRanges are equal, then + // we know we were able to represent the actual mathematical intersection + // of CR0 and CR1, and can use the same to generate an icmp instruction. + // + // Given what we're doing here and the semantics of guards, it would + // actually be correct to just use SubsetIntersect, but that may be too + // aggressive in cases we care about. + auto SubsetIntersect = CR0.inverse().unionWith(CR1.inverse()).inverse(); + auto SupersetIntersect = CR0.intersectWith(CR1); + + APInt NewRHSAP; + CmpInst::Predicate Pred; + if (SubsetIntersect == SupersetIntersect && + SubsetIntersect.getEquivalentICmp(Pred, NewRHSAP)) { if (InsertPt) { - ConstantInt *NewRHS = - RHS0->getValue().ugt(RHS1->getValue()) ? RHS0 : RHS1; - Result = new ICmpInst(InsertPt, ICmpInst::ICMP_UGT, LHS, NewRHS, - "wide.chk"); + ConstantInt *NewRHS = ConstantInt::get(Cond0->getContext(), NewRHSAP); + Result = new ICmpInst(InsertPt, Pred, LHS, NewRHS, "wide.chk"); } - return true; } } diff --git a/test/Transforms/GuardWidening/basic.ll b/test/Transforms/GuardWidening/basic.ll index cb49eebcbab..5b746a5d7dd 100644 --- a/test/Transforms/GuardWidening/basic.ll +++ b/test/Transforms/GuardWidening/basic.ll @@ -126,7 +126,7 @@ leave: define void @f_5(i32 %a) { ; CHECK-LABEL: @f_5( entry: -; CHECK: %wide.chk = icmp ugt i32 %a, 10 +; CHECK: %wide.chk = icmp uge i32 %a, 11 ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] ; CHECK: br i1 undef, label %left, label %right @@ -335,3 +335,47 @@ entry: call void(i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] ret void } + +define void @f_13(i32 %a) { +; CHECK-LABEL: @f_13( +entry: +; CHECK: %wide.chk = icmp ult i32 %a, 10 +; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ] +; CHECK: br i1 undef, label %left, label %right + + %cond_0 = icmp ult i32 %a, 14 + call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] + br i1 undef, label %left, label %right + +left: + %cond_1 = icmp slt i32 %a, 10 + call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] + ret void + +right: + ret void +} + +define void @f_14(i32 %a) { +; CHECK-LABEL: @f_14( +entry: +; CHECK: %cond_0 = icmp ult i32 %a, 14 +; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] +; CHECK: br i1 undef, label %left, label %right + + %cond_0 = icmp ult i32 %a, 14 + call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ] + br i1 undef, label %left, label %right + +left: +; CHECK: left: +; CHECK: %cond_1 = icmp sgt i32 %a, 10 +; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] + + %cond_1 = icmp sgt i32 %a, 10 + call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ] + ret void + +right: + ret void +}