SimplifyCFG: Teach switch generation some patterns that instcombine forms.

This allows us to create switches even if instcombine has munged two of the
incombing compares into one and some bit twiddling. This was motivated by enum
compares that are common in clang.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185632 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer 2013-07-04 14:22:02 +00:00
parent 98abba7b66
commit 32d15d90c4
2 changed files with 63 additions and 1 deletions

View File

@ -40,12 +40,14 @@
#include "llvm/Support/ConstantRange.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/NoFolder.h"
#include "llvm/Support/PatternMatch.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <algorithm>
#include <map>
#include <set>
using namespace llvm;
using namespace PatternMatch;
static cl::opt<unsigned>
PHINodeFoldingThreshold("phi-node-folding-threshold", cl::Hidden, cl::init(1),
@ -432,7 +434,24 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra,
// If this is an icmp against a constant, handle this as one of the cases.
if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
Value *RHSVal;
ConstantInt *RHSC;
if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ:ICmpInst::ICMP_NE)) {
// (x & ~2^x) == y --> x == y || x == y|2^x
// This undoes a transformation done by instcombine to fuse 2 compares.
if (match(ICI->getOperand(0),
m_And(m_Value(RHSVal), m_ConstantInt(RHSC)))) {
APInt Not = ~RHSC->getValue();
if (Not.isPowerOf2()) {
Vals.push_back(C);
Vals.push_back(
ConstantInt::get(C->getContext(), C->getValue() | Not));
UsedICmps++;
return RHSVal;
}
}
UsedICmps++;
Vals.push_back(C);
return I->getOperand(0);
@ -443,6 +462,13 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra,
ConstantRange Span =
ConstantRange::makeICmpRegion(ICI->getPredicate(), C->getValue());
// Shift the range if the compare is fed by an add. This is the range
// compare idiom as emitted by instcombine.
bool hasAdd =
match(I->getOperand(0), m_Add(m_Value(RHSVal), m_ConstantInt(RHSC)));
if (hasAdd)
Span = Span.subtract(RHSC->getValue());
// If this is an and/!= check then we want to optimize "x ugt 2" into
// x != 0 && x != 1.
if (!isEQ)
@ -455,7 +481,7 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra,
for (APInt Tmp = Span.getLower(); Tmp != Span.getUpper(); ++Tmp)
Vals.push_back(ConstantInt::get(V->getContext(), Tmp));
UsedICmps++;
return I->getOperand(0);
return hasAdd ? RHSVal : I->getOperand(0);
}
return 0;
}

View File

@ -479,3 +479,39 @@ return:
; CHECK: ret void
}
define void @test18(i32 %arg) {
bb:
%tmp = and i32 %arg, -2
%tmp1 = icmp eq i32 %tmp, 8
%tmp2 = icmp eq i32 %arg, 10
%tmp3 = or i1 %tmp1, %tmp2
%tmp4 = icmp eq i32 %arg, 11
%tmp5 = or i1 %tmp3, %tmp4
%tmp6 = icmp eq i32 %arg, 12
%tmp7 = or i1 %tmp5, %tmp6
br i1 %tmp7, label %bb19, label %bb8
bb8: ; preds = %bb
%tmp9 = add i32 %arg, -13
%tmp10 = icmp ult i32 %tmp9, 2
%tmp11 = icmp eq i32 %arg, 16
%tmp12 = or i1 %tmp10, %tmp11
%tmp13 = icmp eq i32 %arg, 17
%tmp14 = or i1 %tmp12, %tmp13
%tmp15 = icmp eq i32 %arg, 18
%tmp16 = or i1 %tmp14, %tmp15
%tmp17 = icmp eq i32 %arg, 15
%tmp18 = or i1 %tmp16, %tmp17
br i1 %tmp18, label %bb19, label %bb20
bb19: ; preds = %bb8, %bb
tail call void @foo1()
br label %bb20
bb20: ; preds = %bb19, %bb8
ret void
; CHECK: @test18
; CHECK: %arg.off = add i32 %arg, -8
; CHECK: icmp ult i32 %arg.off, 11
}