[llvm-commits] [llvm] r122045 - in /llvm/trunk: include/llvm/Support/ConstantRange.h lib/Transforms/Utils/SimplifyCFG.cpp test/Transforms/SimplifyCFG/switch_create.ll

Nick Lewycky nicholas at mxc.ca
Fri Dec 17 00:30:55 PST 2010


Chris Lattner wrote:
> Author: lattner
> Date: Fri Dec 17 00:20:15 2010
> New Revision: 122045
>
> URL: http://llvm.org/viewvc/llvm-project?rev=122045&view=rev
> Log:
> improve switch formation to handle small range
> comparisons formed by comparisons.  For example,
> this:
>
> void foo(unsigned x) {
>    if (x == 0 || x == 1 || x == 3 || x == 4 || x == 6)
>      bar();
> }
>
> compiles into:
>
> _foo:                                   ## @foo
> ## BB#0:                                ## %entry
> 	cmpl	$6, %edi
> 	ja	LBB0_2
> ## BB#1:                                ## %entry
> 	movl	%edi, %eax
> 	movl	$91, %ecx
> 	btq	%rax, %rcx
> 	jb	LBB0_3
>
> instead of:
>
> _foo:                                   ## @foo
> ## BB#0:                                ## %entry
> 	cmpl	$2, %edi
> 	jb	LBB0_4
> ## BB#1:                                ## %switch.early.test
> 	cmpl	$6, %edi
> 	ja	LBB0_3
> ## BB#2:                                ## %switch.early.test
> 	movl	%edi, %eax
> 	movl	$88, %ecx
> 	btq	%rax, %rcx
> 	jb	LBB0_4
>
> This catches a bunch of cases in GCC, which look like this:
>
>   %804 = load i32* @which_alternative, align 4, !tbaa !0
>   %805 = icmp ult i32 %804, 2
>   %806 = icmp eq i32 %804, 3
>   %or.cond121 = or i1 %805, %806
>   %807 = icmp eq i32 %804, 4
>   %or.cond124 = or i1 %or.cond121, %807
>   br i1 %or.cond124, label %.thread, label %808
>
> turning this into a range comparison.
>
>
> Modified:
>      llvm/trunk/include/llvm/Support/ConstantRange.h
>      llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
>      llvm/trunk/test/Transforms/SimplifyCFG/switch_create.ll
>
> Modified: llvm/trunk/include/llvm/Support/ConstantRange.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ConstantRange.h?rev=122045&r1=122044&r2=122045&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/ConstantRange.h (original)
> +++ llvm/trunk/include/llvm/Support/ConstantRange.h Fri Dec 17 00:20:15 2010
> @@ -54,7 +54,7 @@
>     /// @brief Initialize a range of values explicitly. This will assert out if
>     /// Lower==Upper and Lower != Min or Max value for its type. It will also
>     /// assert out if the two APInt's are not the same bit width.
> -  ConstantRange(const APInt&  Lower, const APInt&  Upper);
> +  ConstantRange(const APInt&Lower, const APInt&Upper);
>
>     /// makeICmpRegion - Produce the smallest range that contains all values that
>     /// might satisfy the comparison specified by Pred when compared to any value
>
> Modified: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp?rev=122045&r1=122044&r2=122045&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp (original)
> +++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp Fri Dec 17 00:20:15 2010
> @@ -28,6 +28,7 @@
>   #include "llvm/ADT/Statistic.h"
>   #include "llvm/ADT/STLExtras.h"
>   #include "llvm/Support/CFG.h"
> +#include "llvm/Support/ConstantRange.h"
>   #include "llvm/Support/Debug.h"
>   #include "llvm/Support/raw_ostream.h"
>   #include<algorithm>
> @@ -305,11 +306,33 @@
>
>     // If this is an icmp against a constant, handle this as one of the cases.
>     if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
> -    if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE))
> -      if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
> +    if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
> +      if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ:ICmpInst::ICMP_NE)) {
>           Vals.push_back(C);
>           return I->getOperand(0);
>         }
> +
> +      // If we have "x ult 3" comparison, for example, then we can add 0,1,2 to
> +      // the set.
> +      ConstantRange Span =
> +        ConstantRange::makeICmpRegion(ICI->getPredicate(),
> +                                      ConstantRange(C->getValue()));

This simplifies to:

   ConstantRange Span = ICmpInst::makeConstantRange(ICI->getPredicate(), 
C->getValue());

Nick

> +
> +      // If this is an and/!= check then we want to optimize "x ugt 2" into
> +      // x != 0&&  x != 1.
> +      if (!isEQ)
> +        Span = Span.inverse();
> +
> +      // If there are a ton of values, we don't want to make a ginormous switch.
> +      if (Span.getSetSize().getZExtValue()>  8 || Span.isEmptySet() ||
> +          // We don't handle wrapped sets yet.
> +          Span.isWrappedSet())
> +        return 0;
> +
> +      for (APInt Tmp = Span.getLower(); Tmp != Span.getUpper(); ++Tmp)
> +        Vals.push_back(ConstantInt::get(V->getContext(), Tmp));
> +      return I->getOperand(0);
> +    }
>       return 0;
>     }
>
>
> Modified: llvm/trunk/test/Transforms/SimplifyCFG/switch_create.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/switch_create.ll?rev=122045&r1=122044&r2=122045&view=diff
> ==============================================================================
> --- llvm/trunk/test/Transforms/SimplifyCFG/switch_create.ll (original)
> +++ llvm/trunk/test/Transforms/SimplifyCFG/switch_create.ll Fri Dec 17 00:20:15 2010
> @@ -351,4 +351,73 @@
>     ret void
>   ; CHECK: @test12
>
> -}
> \ No newline at end of file
> +}
> +
> +; test13 - handle switch formation with ult.
> +define void @test13(i32 %x) nounwind ssp noredzone {
> +entry:
> +  %cmp = icmp ult i32 %x, 2
> +  br i1 %cmp, label %if.then, label %lor.lhs.false3
> +
> +lor.lhs.false3:                                   ; preds = %lor.lhs.false
> +  %cmp5 = icmp eq i32 %x, 3
> +  br i1 %cmp5, label %if.then, label %lor.lhs.false6
> +
> +lor.lhs.false6:                                   ; preds = %lor.lhs.false3
> +  %cmp8 = icmp eq i32 %x, 4
> +  br i1 %cmp8, label %if.then, label %lor.lhs.false9
> +
> +lor.lhs.false9:                                   ; preds = %lor.lhs.false6
> +  %cmp11 = icmp eq i32 %x, 6
> +  br i1 %cmp11, label %if.then, label %if.end
> +
> +if.then:                                          ; preds = %lor.lhs.false9, %lor.lhs.false6, %lor.lhs.false3, %lor.lhs.false, %entry
> +  call void @foo1() noredzone
> +  br label %if.end
> +
> +if.end:                                           ; preds = %if.then, %lor.lhs.false9
> +  ret void
> +; CHECK: @test13
> +; CHECK:  switch i32 %x, label %if.end [
> +; CHECK:     i32 6, label %if.then
> +; CHECK:     i32 4, label %if.then
> +; CHECK:     i32 3, label %if.then
> +; CHECK:     i32 1, label %if.then
> +; CHECK:     i32 0, label %if.then
> +; CHECK:   ]
> +}
> +
> +; test14 - handle switch formation with ult.
> +define void @test14(i32 %x) nounwind ssp noredzone {
> +entry:
> +  %cmp = icmp ugt i32 %x, 2
> +  br i1 %cmp, label %lor.lhs.false3, label %if.then
> +
> +lor.lhs.false3:                                   ; preds = %lor.lhs.false
> +  %cmp5 = icmp ne i32 %x, 3
> +  br i1 %cmp5, label %lor.lhs.false6, label %if.then
> +
> +lor.lhs.false6:                                   ; preds = %lor.lhs.false3
> +  %cmp8 = icmp ne i32 %x, 4
> +  br i1 %cmp8, label %lor.lhs.false9, label %if.then
> +
> +lor.lhs.false9:                                   ; preds = %lor.lhs.false6
> +  %cmp11 = icmp ne i32 %x, 6
> +  br i1 %cmp11, label %if.end, label %if.then
> +
> +if.then:                                          ; preds = %lor.lhs.false9, %lor.lhs.false6, %lor.lhs.false3, %lor.lhs.false, %entry
> +  call void @foo1() noredzone
> +  br label %if.end
> +
> +if.end:                                           ; preds = %if.then, %lor.lhs.false9
> +  ret void
> +; CHECK: @test14
> +; CHECK:  switch i32 %x, label %if.end [
> +; CHECK:     i32 6, label %if.then
> +; CHECK:     i32 4, label %if.then
> +; CHECK:     i32 3, label %if.then
> +; CHECK:     i32 1, label %if.then
> +; CHECK:     i32 0, label %if.then
> +; CHECK:   ]
> +}
> +
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>




More information about the llvm-commits mailing list