diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index ac0c01e3c7b..e158c11b1fd 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2075,6 +2075,37 @@ Instruction *InstCombiner::visitBranchInst(BranchInst &BI) { Instruction *InstCombiner::visitSwitchInst(SwitchInst &SI) { Value *Cond = SI.getCondition(); + unsigned BitWidth = cast(Cond->getType())->getBitWidth(); + APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0); + computeKnownBits(Cond, KnownZero, KnownOne); + unsigned LeadingKnownZeros = KnownZero.countLeadingOnes(); + unsigned LeadingKnownOnes = KnownOne.countLeadingOnes(); + + // Compute the number of leading bits we can ignore. + for (auto &C : SI.cases()) { + LeadingKnownZeros = std::min( + LeadingKnownZeros, C.getCaseValue()->getValue().countLeadingZeros()); + LeadingKnownOnes = std::min( + LeadingKnownOnes, C.getCaseValue()->getValue().countLeadingOnes()); + } + + unsigned NewWidth = BitWidth - std::max(LeadingKnownZeros, LeadingKnownOnes); + + // Truncate the condition operand if the new type is equal to or larger than + // the largest legal integer type. We need to be conservative here since + // x86 generates redundant zero-extenstion instructions if the operand is + // truncated to i8 or i16. + if (BitWidth > NewWidth && NewWidth >= DL->getLargestLegalIntTypeSize()) { + IntegerType *Ty = IntegerType::get(SI.getContext(), NewWidth); + Builder->SetInsertPoint(&SI); + Value *NewCond = Builder->CreateTrunc(SI.getCondition(), Ty, "trunc"); + SI.setCondition(NewCond); + + for (auto &C : SI.cases()) + static_cast(&C)->setValue( + ConstantInt::get(Ty, C.getCaseValue()->getValue().getZExtValue())); + } + if (Instruction *I = dyn_cast(Cond)) { if (I->getOpcode() == Instruction::Add) if (ConstantInt *AddRHS = dyn_cast(I->getOperand(1))) { diff --git a/test/Transforms/InstCombine/narrow-switch.ll b/test/Transforms/InstCombine/narrow-switch.ll new file mode 100644 index 00000000000..f649afcce80 --- /dev/null +++ b/test/Transforms/InstCombine/narrow-switch.ll @@ -0,0 +1,61 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + +; CHECK-LABEL: define i32 @positive1 +; CHECK: switch i32 +; CHECK: i32 10, label +; CHECK: i32 100, label +; CHECK: i32 1001, label + +define i32 @positive1(i64 %a) { +entry: + %and = and i64 %a, 4294967295 + switch i64 %and, label %sw.default [ + i64 10, label %return + i64 100, label %sw.bb1 + i64 1001, label %sw.bb2 + ] + +sw.bb1: + br label %return + +sw.bb2: + br label %return + +sw.default: + br label %return + +return: + %retval.0 = phi i32 [ 24, %sw.default ], [ 123, %sw.bb2 ], [ 213, %sw.bb1 ], [ 231, %entry ] + ret i32 %retval.0 +} + +; CHECK-LABEL: define i32 @negative1 +; CHECK: switch i32 +; CHECK: i32 -10, label +; CHECK: i32 -100, label +; CHECK: i32 -1001, label + +define i32 @negative1(i64 %a) { +entry: + %or = or i64 %a, -4294967296 + switch i64 %or, label %sw.default [ + i64 -10, label %return + i64 -100, label %sw.bb1 + i64 -1001, label %sw.bb2 + ] + +sw.bb1: + br label %return + +sw.bb2: + br label %return + +sw.default: + br label %return + +return: + %retval.0 = phi i32 [ 24, %sw.default ], [ 123, %sw.bb2 ], [ 213, %sw.bb1 ], [ 231, %entry ] + ret i32 %retval.0 +}