[llvm] r335020 - [SimplifyIndVars] Eliminate redundant truncs

Maxim Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 27 00:59:28 PDT 2018


Hi Mikael,

That's a nasty case, maybe more than one case. :) I was able to fix this particular situation with https://reviews.llvm.org/D51286, but it's not clear for me why underlying algorithm is expected to preserve LCSSA. I will dig a bit more and try to construct something more tricky which will expose the problem.

-- Max

-----Original Message-----
From: Mikael Holmén [mailto:mikael.holmen at ericsson.com] 
Sent: Thursday, August 23, 2018 12:40 PM
To: Maxim Kazantsev <max.kazantsev at azul.com>
Cc: llvm-commits at lists.llvm.org
Subject: Re: [llvm] r335020 - [SimplifyIndVars] Eliminate redundant truncs

Hi,

On 08/23/2018 04:18 AM, Maxim Kazantsev wrote:
> Hi Mikael,
> 
> Thanks for finding this! Looks like a completely different issue, 
> rL335816 was against another assertion failure. Could you please file 
> this on bugs.llvm.org? I cannot take a look into it today, but will do 
> it within next couple of days unless someone else will pick it up 
> faster than me. :)
> 

Sure, here's the PR:
  https://bugs.llvm.org/show_bug.cgi?id=38674

Thanks,
Mikael

> -- Max
> 
> -----Original Message-----
> From: Mikael Holmén [mailto:mikael.holmen at ericsson.com]
> Sent: Wednesday, August 22, 2018 8:41 PM
> To: Maxim Kazantsev <max.kazantsev at azul.com>
> Cc: llvm-commits at lists.llvm.org
> Subject: Re: [llvm] r335020 - [SimplifyIndVars] Eliminate redundant 
> truncs
> 
> Hi again!
> 
> I found another case which starts crashing with r335020. (It seems to 
> be something else than the previous crash so r335816 doesn't help.)
> 
> opt -S -o - bbi-16913.ll -indvars
> 
> crashes with
> 
> opt: ../lib/Transforms/Scalar/IndVarSimplify.cpp:2519: bool (anonymous namespace)::IndVarSimplify::run(llvm::Loop *): Assertion `L->isRecursivelyLCSSAForm(*DT, *LI) && "Indvars did not preserve LCSSA!"' failed.
> 
> The function looks like this when the assertion fails
> 
> define i32 @f1() {
> entry:
>     br label %for.cond1.preheader
> 
> for.cond1.preheader:                              ; preds = %for.end9,
> %entry
>     br label %for.cond4.preheader
> 
> for.cond4.preheader:                              ; preds = %for.end,
> %for.cond1.preheader
>     %zext = zext i16 1 to i32
>     br label %for.body6
> 
> for.cond4:                                        ; preds = %for.body6
>     %cmp5 = icmp ult i32 %inc, 2
>     br i1 %cmp5, label %for.body6, label %for.end
> 
> for.body6:                                        ; preds = %for.cond4,
> %for.cond4.preheader
>     %storemerge26 = phi i32 [ 0, %for.cond4.preheader ], [ %inc, %for.cond4 ]
>     %0 = icmp eq i32 %storemerge26, %zext
>     %inc = add nuw nsw i32 %storemerge26, 1
>     br i1 %0, label %return.loopexit, label %for.cond4
> 
> for.end:                                          ; preds = %for.cond4
>     br i1 false, label %for.cond4.preheader, label %for.end9
> 
> for.end9:                                         ; preds = %for.end
>     br i1 false, label %for.cond1.preheader, label %return.loopexit3
> 
> return.loopexit:                                  ; preds = %for.body6
>     unreachable
> 
> return.loopexit3:                                 ; preds = %for.end9
>     %inc11.lcssa = phi i32 [ %zext, %for.end9 ]
>     br label %return
> 
> return:                                           ; preds =
> %return.loopexit3
>     ret i32 %inc11.lcssa
> }
> 
> Regards,
> Mikael
> 
> On 06/28/2018 10:37 AM, Mikael Holmén via llvm-commits wrote:
>>
>>
>> On 06/28/2018 10:27 AM, Maxim Kazantsev wrote:
>>> Yes indeed. I think we also have some other pieces of code that get 
>>> pessimized by such users (i.e. some transform is rejected because of 
>>> some bad user). It would be interesting to look for such cases.
>>>
>>> BTW, the assertion failire should be gone with
>>> https://reviews.llvm.org/rL335816 .
>>>
>>
>> Yep!
>>
>> Thanks,
>> Mikael
>>
>>> -----Original Message-----
>>> From: Mikael Holmén [mailto:mikael.holmen at ericsson.com]
>>> Sent: Thursday, June 28, 2018 2:58 PM
>>> To: Maxim Kazantsev <max.kazantsev at azul.com>
>>> Cc: llvm-commits at lists.llvm.org
>>> Subject: Re: [llvm] r335020 - [SimplifyIndVars] Eliminate redundant 
>>> truncs
>>>
>>>
>>>
>>> On 06/28/2018 09:47 AM, Maxim Kazantsev wrote:
>>>> Interesting. A user in block unreachable from entry, I didn't think 
>>>> we can end up with something like this. :) I'll come up with a fix 
>>>> soon. Thanks for test!
>>>
>>> Yes I don't know how many problems I've stumbled upon now due to 
>>> weird code in blocks that are unreachable from entry that several 
>>> passes then flips out on.
>>>
>>> I hope the gain from allowing such code is huge since there are 
>>> certainly many problems with it.
>>>
>>> Thanks,
>>> Mikael
>>>
>>>>
>>>> -- Max
>>>>
>>>> -----Original Message-----
>>>> From: Mikael Holmén [mailto:mikael.holmen at ericsson.com]
>>>> Sent: Thursday, June 28, 2018 2:34 PM
>>>> To: Maxim Kazantsev <max.kazantsev at azul.com>
>>>> Cc: llvm-commits at lists.llvm.org
>>>> Subject: Re: [llvm] r335020 - [SimplifyIndVars] Eliminate redundant 
>>>> truncs
>>>>
>>>> Hi Max,
>>>>
>>>> With
>>>>
>>>>      opt -S -o - bbi-15696.ll -indvars
>>>>
>>>> I trigger one of the new asserts in this patch:
>>>>
>>>> opt: ../lib/Transforms/Utils/SimplifyIndVar.cpp:540: bool 
>>>> (anonymous namespace)::SimplifyIndvar::eliminateTrunc(llvm::TruncInst *):
>>>> Assertion
>>>> `L->contains(ICI->getParent()) && "LCSSA form broken?"' failed.
>>>> Stack dump:
>>>> 0.      Program arguments: build-all/bin/opt -S -o - bbi-15696.ll 
>>>> -indvars 1.      Running pass 'Function Pass Manager' on module 
>>>> 'bbi-15696.ll'.
>>>> 2.      Running pass 'Loop Pass Manager' on function '@f3'
>>>> 3.      Running pass 'Induction Variable Simplification' on basic 
>>>> block '%bb1'
>>>> #0 0x0000000001ff1b44 PrintStackTraceSignalHandler(void*)
>>>> (build-all/bin/opt+0x1ff1b44)
>>>> #1 0x0000000001fefdb0 llvm::sys::RunSignalHandlers()
>>>> (build-all/bin/opt+0x1fefdb0)
>>>> #2 0x0000000001ff1ea8 SignalHandler(int)
>>>> (build-all/bin/opt+0x1ff1ea8)
>>>> #3 0x00007f314bd38330 __restore_rt
>>>> (/lib/x86_64-linux-gnu/libpthread.so.0+0x10330)
>>>> #4 0x00007f314a927c37 gsignal
>>>> /build/eglibc-ripdx6/eglibc-2.19/signal/../nptl/sysdeps/unix/sysv/l
>>>> i
>>>> nu
>>>> x/raise.c:56:0
>>>> #5 0x00007f314a92b028 abort
>>>> /build/eglibc-ripdx6/eglibc-2.19/stdlib/abort.c:91:0
>>>> #6 0x00007f314a920bf6 __assert_fail_base
>>>> /build/eglibc-ripdx6/eglibc-2.19/assert/assert.c:92:0
>>>> #7 0x00007f314a920ca2 (/lib/x86_64-linux-gnu/libc.so.6+0x2fca2)
>>>> #8 0x00000000020d2906 (anonymous
>>>> namespace)::SimplifyIndvar::eliminateIVUser(llvm::Instruction*,
>>>> llvm::Instruction*) (build-all/bin/opt+0x20d2906)
>>>> #9 0x00000000020cf81b llvm::simplifyUsersOfIV(llvm::PHINode*,
>>>> llvm::ScalarEvolution*, llvm::DominatorTree*, llvm::LoopInfo*, 
>>>> llvm::SmallVectorImpl<llvm::WeakTrackingVH>&, llvm::SCEVExpander&,
>>>> llvm::IVVisitor*) (build-all/bin/opt+0x20cf81b)
>>>> #10 0x0000000001ded2c1 (anonymous
>>>> namespace)::IndVarSimplify::run(llvm::Loop*)
>>>> (build-all/bin/opt+0x1ded2c1)
>>>> #11 0x0000000001df202c (anonymous
>>>> namespace)::IndVarSimplifyLegacyPass::runOnLoop(llvm::Loop*,
>>>> llvm::LPPassManager&) (build-all/bin/opt+0x1df202c)
>>>> #12 0x0000000001533995
>>>> llvm::LPPassManager::runOnFunction(llvm::Function&)
>>>> (build-all/bin/opt+0x1533995)
>>>> #13 0x0000000001a7f5da
>>>> llvm::FPPassManager::runOnFunction(llvm::Function&)
>>>> (build-all/bin/opt+0x1a7f5da)
>>>> #14 0x0000000001a7f838
>>>> llvm::FPPassManager::runOnModule(llvm::Module&)
>>>> (build-all/bin/opt+0x1a7f838)
>>>> #15 0x0000000001a7fd6d
>>>> llvm::legacy::PassManagerImpl::run(llvm::Module&)
>>>> (build-all/bin/opt+0x1a7fd6d)
>>>> #16 0x0000000000744f4c main (build-all/bin/opt+0x744f4c)
>>>> #17 0x00007f314a912f45 __libc_start_main
>>>> /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:321:0
>>>> #18 0x000000000072e2ad _start (build-all/bin/opt+0x72e2ad) Abort
>>>>
>>>> When the assertion fails TI is
>>>>       %_tmp15 = trunc i32 %e.5.0 to i16 and ICI is
>>>>       %_tmp24 = icmp slt i16 %_tmp15, 0 and L is
>>>>      Loop at depth 1 containing:
>>>> %bb1<header>,%bb2,%bb3,%bb4,%bb6<latch><exiting>
>>>>
>>>> %bb5 which contains the icmp is only reached from itself
>>>>
>>>> bb5:                                              ; preds = %bb5,
>>>> %bb5
>>>>       %_tmp24 = icmp slt i16 %_tmp15, 0
>>>>       br i1 %_tmp24, label %bb5, label %bb5
>>>>
>>>> Regards,
>>>> Mikael
>>>>
>>>> On 06/19/2018 06:48 AM, Max Kazantsev via llvm-commits wrote:
>>>>> Author: mkazantsev
>>>>> Date: Mon Jun 18 21:48:34 2018
>>>>> New Revision: 335020
>>>>>
>>>>> URL: http://llvm.org/viewvc/llvm-project?rev=335020&view=rev
>>>>> Log:
>>>>> [SimplifyIndVars] Eliminate redundant truncs
>>>>>
>>>>> This patch adds logic to deal with the following constructions:
>>>>>
>>>>>       %iv = phi i64 ...
>>>>>       %trunc = trunc i64 %iv to i32
>>>>>       %cmp = icmp <pred> i32 %trunc, %invariant
>>>>>
>>>>> Replacing it with
>>>>>       %iv = phi i64 ...
>>>>>       %cmp = icmp <pred> i64 %iv, sext/zext(%invariant)
>>>>>
>>>>> In case if it is legal. Specifically, if `%iv` has signed 
>>>>> comparison users, it is required that `sext(trunc(%iv)) == %iv`, 
>>>>> and if it has unsigned comparison uses then we require `zext(trunc(%iv)) == %iv`.
>>>>> The current implementation bails if `%trunc` has other uses than 
>>>>> `icmp`, but in theory we can handle more cases here (e.g. if the 
>>>>> user of trunc is bitcast).
>>>>>
>>>>> Differential Revision: https://reviews.llvm.org/D47928 Reviewed By:
>>>>> reames
>>>>>
>>>>> Added:
>>>>>         
>>>>> llvm/trunk/test/Transforms/IndVarSimplify/eliminate-trunc.ll
>>>>> Modified:
>>>>>         llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp
>>>>>         llvm/trunk/test/Transforms/IndVarSimplify/ada-loops.ll
>>>>>         
>>>>> llvm/trunk/test/Transforms/IndVarSimplify/widen-loop-comp.ll
>>>>>
>>>>> Modified: llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Util
>>>>> s /S i mplifyIndVar.cpp?rev=335020&r1=335019&r2=335020&view=diff
>>>>> ==================================================================
>>>>> =
>>>>> ==
>>>>> =
>>>>> ========
>>>>> --- llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp (original)
>>>>> +++ llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp Mon Jun 18
>>>>> +++ 21:48:34 2018
>>>>> @@ -81,6 +81,7 @@ namespace {
>>>>>          bool replaceIVUserWithLoopInvariant(Instruction 
>>>>> *UseInst);
>>>>>          bool eliminateOverflowIntrinsic(CallInst *CI);
>>>>> +    bool eliminateTrunc(TruncInst *TI);
>>>>>          bool eliminateIVUser(Instruction *UseInst, Instruction 
>>>>> *IVOperand);
>>>>>          bool makeIVComparisonInvariant(ICmpInst *ICmp, Value 
>>>>> *IVOperand);
>>>>>          void eliminateIVComparison(ICmpInst *ICmp, Value 
>>>>> *IVOperand); @@
>>>>> -494,6 +495,93 @@ bool SimplifyIndvar::eliminateOverflowIn
>>>>>        return true;
>>>>>      }
>>>>> +bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) {
>>>>> +  // It is always legal to replace
>>>>> +  //   icmp <pred> i32 trunc(iv), n
>>>>> +  // with
>>>>> +  //   icmp <pred> i64 sext(trunc(iv)), sext(n), if pred is 
>>>>> +signed
>>>>> predicate.
>>>>> +  // Or with
>>>>> +  //   icmp <pred> i64 zext(trunc(iv)), zext(n), if pred is
>>>>> unsigned predicate.
>>>>> +  // Or with either of these if pred is an equality predicate.
>>>>> +  //
>>>>> +  // If we can prove that iv == sext(trunc(iv)) or iv ==
>>>>> +zext(trunc(iv)) for
>>>>> +  // every comparison which uses trunc, it means that we can 
>>>>> +replace each of
>>>>> +  // them with comparison of iv against sext/zext(n). We no 
>>>>> +longer need trunc
>>>>> +  // after that.
>>>>> +  //
>>>>> +  // TODO: Should we do this if we can widen *some* comparisons, 
>>>>> +but not all
>>>>> +  // of them? Sometimes it is enough to enable other 
>>>>> +optimizations, but the
>>>>> +  // trunc instruction will stay in the loop.
>>>>> +  Value *IV = TI->getOperand(0);
>>>>> +  Type *IVTy = IV->getType();
>>>>> +  const SCEV *IVSCEV = SE->getSCEV(IV);
>>>>> +  const SCEV *TISCEV = SE->getSCEV(TI);
>>>>> +
>>>>> +  // Check if iv == zext(trunc(iv)) and if iv == sext(trunc(iv)).
>>>>> +If  so, we can  // get rid of trunc  bool DoesSExtCollapse = 
>>>>> +false;  bool DoesZExtCollapse = false;  if (IVSCEV ==
>>>>> + SE->getSignExtendExpr(TISCEV, IVTy))
>>>>> +    DoesSExtCollapse = true;
>>>>> +  if (IVSCEV == SE->getZeroExtendExpr(TISCEV, IVTy))
>>>>> +    DoesZExtCollapse = true;
>>>>> +
>>>>> +  // If neither sext nor zext does collapse, it is not profitable 
>>>>> +to  do any  // transform. Bail.
>>>>> +  if (!DoesSExtCollapse && !DoesZExtCollapse)
>>>>> +    return false;
>>>>> +
>>>>> +  // Collect users of the trunc that look like comparisons 
>>>>> +against
>>>>> invariants.
>>>>> +  // Bail if we find something different.
>>>>> +  SmallVector<ICmpInst *, 4> ICmpUsers;  for (auto *U :
>>>>> +TI->users())  {
>>>>> +    if (ICmpInst *ICI = dyn_cast<ICmpInst>(U)) {
>>>>> +      if (ICI->getOperand(0) == TI &&
>>>>> L->isLoopInvariant(ICI->getOperand(1))) {
>>>>> +        assert(L->contains(ICI->getParent()) && "LCSSA form 
>>>>> +broken?");
>>>>> +        // If we cannot get rid of trunc, bail.
>>>>> +        if (ICI->isSigned() && !DoesSExtCollapse)
>>>>> +          return false;
>>>>> +        if (ICI->isUnsigned() && !DoesZExtCollapse)
>>>>> +          return false;
>>>>> +        // For equality, either signed or unsigned works.
>>>>> +        ICmpUsers.push_back(ICI);
>>>>> +      } else
>>>>> +        return false;
>>>>> +    } else
>>>>> +      return false;
>>>>> +  }
>>>>> +
>>>>> +  // Replace all comparisons against trunc with comparisons 
>>>>> +against
>>>>> IV.
>>>>> +  for (auto *ICI : ICmpUsers) {
>>>>> +    auto *Op1 = ICI->getOperand(1);
>>>>> +    Instruction *Ext = nullptr;
>>>>> +    // For signed/unsigned predicate, replace the old comparison
>>>>> with comparison
>>>>> +    // of immediate IV against sext/zext of the invariant argument.
>>>>> If we can
>>>>> +    // use either sext or zext (i.e. we are dealing with equality
>>>>> predicate),
>>>>> +    // then prefer zext as a more canonical form.
>>>>> +    // TODO: If we see a signed comparison which can be turned 
>>>>> +into
>>>>> unsigned,
>>>>> +    // we can do it here for canonicalization purposes.
>>>>> +    if (ICI->isUnsigned() || (ICI->isEquality() &&
>>>>> DoesZExtCollapse)) {
>>>>> +      assert(DoesZExtCollapse && "Unprofitable zext?");
>>>>> +      Ext = new ZExtInst(Op1, IVTy, "zext", ICI);
>>>>> +    } else {
>>>>> +      assert(DoesSExtCollapse && "Unprofitable sext?");
>>>>> +      Ext = new SExtInst(Op1, IVTy, "sext", ICI);
>>>>> +    }
>>>>> +    bool Changed;
>>>>> +    L->makeLoopInvariant(Ext, Changed);
>>>>> +    (void)Changed;
>>>>> +    ICmpInst *NewICI = new ICmpInst(ICI, ICI->getPredicate(), IV,
>>>>> Ext);
>>>>> +    ICI->replaceAllUsesWith(NewICI);
>>>>> +    DeadInsts.emplace_back(ICI);
>>>>> +  }
>>>>> +
>>>>> +  // Trunc no longer needed.
>>>>> +  TI->replaceAllUsesWith(UndefValue::get(TI->getType()));
>>>>> +  DeadInsts.emplace_back(TI);
>>>>> +  return true;
>>>>> +}
>>>>> +
>>>>>      /// Eliminate an operation that consumes a simple IV and has 
>>>>> no observable
>>>>>      /// side-effect given the range of IV values.  IVOperand is 
>>>>> guaranteed SCEVable,
>>>>>      /// but UseInst may not be.
>>>>> @@ -518,6 +606,10 @@ bool SimplifyIndvar::eliminateIVUser(Ins
>>>>>          if (eliminateOverflowIntrinsic(CI))
>>>>>            return true;
>>>>> +  if (auto *TI = dyn_cast<TruncInst>(UseInst))
>>>>> +    if (eliminateTrunc(TI))
>>>>> +      return true;
>>>>> +
>>>>>        if (eliminateIdentitySCEV(UseInst, IVOperand))
>>>>>          return true;
>>>>>
>>>>> Modified: llvm/trunk/test/Transforms/IndVarSimplify/ada-loops.ll
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Ind
>>>>> V ar S 
>>>>> implify/ada-loops.ll?rev=335020&r1=335019&r2=335020&view=diff
>>>>> ==================================================================
>>>>> =
>>>>> ==
>>>>> =
>>>>> ========
>>>>> --- llvm/trunk/test/Transforms/IndVarSimplify/ada-loops.ll
>>>>> (original)
>>>>> +++ llvm/trunk/test/Transforms/IndVarSimplify/ada-loops.ll Mon Jun
>>>>> +++ 18
>>>>> +++ 21:48:34 2018
>>>>> @@ -10,12 +10,17 @@
>>>>>      ; don't check that phis are "folded together" because that is 
>>>>> a job
>>>>>      ; for loop strength reduction. But indvars must remove sext, 
>>>>> zext, and add i8.
>>>>>      ;
>>>>> -; CHECK-NOT: {{sext|zext|add i8}}
>>>>>      ; ModuleID = 'ada.bc'
>>>>>      target datalayout =
>>>>> "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32"
>>>>>
>>>>>      target triple = "i686-pc-linux-gnu"
>>>>> +; CHECK-LABEL: @kinds__sbytezero
>>>>> +; CHECK:         bb.thread:
>>>>> +; CHECK:         sext
>>>>> +; CHECK:         bb:
>>>>> +; CHECK-NOT:     {{sext i8|zext i8|add i8|trunc}}
>>>>> +
>>>>>      define void @kinds__sbytezero([256 x i32]* nocapture %a) 
>>>>> nounwind {
>>>>>      bb.thread:
>>>>>          %tmp46 = getelementptr [256 x i32], [256 x i32]* %a, i32 
>>>>> 0,
>>>>> i32 0        ; <i32*> [#uses=1]
>>>>> @@ -36,6 +41,8 @@ return:        ; preds = %bb
>>>>>          ret void
>>>>>      }
>>>>> +; CHECK-LABEL: @kinds__ubytezero
>>>>> +
>>>>>      define void @kinds__ubytezero([256 x i32]* nocapture %a) 
>>>>> nounwind {
>>>>>      bb.thread:
>>>>>          %tmp35 = getelementptr [256 x i32], [256 x i32]* %a, i32 
>>>>> 0,
>>>>> i32 0        ; <i32*> [#uses=1]
>>>>>
>>>>> Added: 
>>>>> llvm/trunk/test/Transforms/IndVarSimplify/eliminate-trunc.ll
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Ind
>>>>> V ar S implify/eliminate-trunc.ll?rev=335020&view=auto
>>>>> ==================================================================
>>>>> =
>>>>> ==
>>>>> =
>>>>> ========
>>>>> --- llvm/trunk/test/Transforms/IndVarSimplify/eliminate-trunc.ll
>>>>> (added)
>>>>> +++ llvm/trunk/test/Transforms/IndVarSimplify/eliminate-trunc.ll
>>>>> +++ Mon Jun 18 21:48:34 2018
>>>>> @@ -0,0 +1,486 @@
>>>>> +; NOTE: Assertions have been autogenerated by 
>>>>> +utils/update_test_checks.py ; RUN: opt -indvars -S < %s | 
>>>>> +FileCheck %s
>>>>> +
>>>>> +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
>>>>> +target triple = "x86_64-unknown-linux-gnu"
>>>>> +
>>>>> +; General case: without extra knowledge, trunc cannot be eliminated.
>>>>> +define void @test_00(i64 %start, i32 %n) { ; ; CHECK-LABEL:
>>>>> + at test_00( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START:%.*]],
>>>>> [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1 ; CHECK-NEXT:
>>>>> +[[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32 ; CHECK-NEXT:
>>>>> +[[CMP:%.*]] = icmp slt i32 [[NARROW_IV]], [[N:%.*]] ; CHECK-NEXT:
>>>>> +br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK:
>>>>> +exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +
>>>>> +define void @test_01(i32 %n) {
>>>>> +;
>>>>> +; CHECK-LABEL: @test_01(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[SEXT:%.*]] = sext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] ;
>>>>> +CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Max value at which we can eliminate trunc: SINT_MAX - 1.
>>>>> +define void @test_02(i32 %n) {
>>>>> +;
>>>>> +; CHECK-LABEL: @test_02(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[SEXT:%.*]] = sext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 2147483646, [[ENTRY:%.*]]
>>>>> ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] ;
>>>>> +CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 2147483646, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; If we start from SINT_MAX then the predicate is always false.
>>>>> +define void @test_03(i32 %n) {
>>>>> +;
>>>>> +; CHECK-LABEL: @test_03(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    br i1 false, label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +;
>>>>> +CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [2147483647, %entry], [%iv.next, %loop]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Minimum value at which we can apply the transform: SINT_MIN + 1.
>>>>> +define void @test_04(i32 %n) {
>>>>> +;
>>>>> +; CHECK-LABEL: @test_04(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[SEXT:%.*]] = sext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ -2147483647, 
>>>>> +[[ENTRY:%.*]]
>>>>> ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], 1 ; CHECK-NEXT:
>>>>> +[[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] ; CHECK-NEXT:    br
>>>>> +i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK:
>>>>> +exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ -2147483647, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; FIXME: Harmful LFTR should be thrown away.
>>>>> +define void @test_05(i32 %n) {
>>>>> +;
>>>>> +; CHECK-LABEL: @test_05(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[N:%.*]], 1 ; CHECK-NEXT:
>>>>> +br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ -2147483648, 
>>>>> +[[ENTRY:%.*]]
>>>>> ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], 1 ; CHECK-NEXT:
>>>>> +[[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32 ; CHECK-NEXT:
>>>>> +[[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]],
>>>>> [[TMP0]]
>>>>> +; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label
>>>>> [[EXIT:%.*]]
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ -2147483648, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Trunc changes the actual value of the IV, so it is invalid to
>>>>> remove it: SINT_MIN - 1.
>>>>> +define void @test_06(i32 %n) {
>>>>> +;
>>>>> +; CHECK-LABEL: @test_06(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ -2147483649, 
>>>>> +[[ENTRY:%.*]]
>>>>> ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32 ;
>>>>> +CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[NARROW_IV]], 
>>>>> +[[N:%.*]] ; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP]], label 
>>>>> +[[EXIT:%.*]] ; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ -2147483649, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; General case: without extra knowledge, trunc cannot be eliminated.
>>>>> +define void @test_00_unsigned(i64 %start, i32 %n) { ; CHECK-LABEL:
>>>>> + at test_00_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[START:%.*]],
>>>>> [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add i64 [[IV]], 1 ; CHECK-NEXT:
>>>>> +[[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32 ; CHECK-NEXT:
>>>>> +[[CMP:%.*]] = icmp ult i32 [[NARROW_IV]], [[N:%.*]] ; CHECK-NEXT:
>>>>> +br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK:
>>>>> +exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; FIXME: Harmful LFTR should be thrown away.
>>>>> +define void @test_01_unsigned(i32 %n) { ; CHECK-LABEL:
>>>>> + at test_01_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[N:%.*]], 1 ; CHECK-NEXT:
>>>>> +br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32 
>>>>> +; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]],
>>>>> [[TMP0]]
>>>>> +; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label
>>>>> [[EXIT:%.*]]
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Max value at which we can eliminate trunc: UINT_MAX - 1.
>>>>> +define void @test_02_unsigned(i32 %n) { ; CHECK-LABEL:
>>>>> + at test_02_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 4294967294, [[ENTRY:%.*]]
>>>>> ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT]] ;
>>>>> +CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 4294967294, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; If we start from UINT_MAX then the predicate is always false.
>>>>> +define void @test_03_unsigned(i32 %n) { ; CHECK-LABEL:
>>>>> + at test_03_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    br i1 false, label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +;
>>>>> +CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 4294967295, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Minimum value at which we can apply the transform: UINT_MIN.
>>>>> +define void @test_04_unsigned(i32 %n) { ; CHECK-LABEL:
>>>>> + at test_04_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[N:%.*]], 1 ; CHECK-NEXT:
>>>>> +br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32 
>>>>> +; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]],
>>>>> [[TMP0]]
>>>>> +; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP]], label
>>>>> [[EXIT:%.*]]
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Start from 1.
>>>>> +define void @test_05_unsigned(i32 %n) { ; CHECK-LABEL:
>>>>> + at test_05_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT]] ;
>>>>> +CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Trunc changes the actual value of the IV, so it is invalid to
>>>>> remove it: UINT_MIN - 1.
>>>>> +define void @test_06_unsigned(i32 %n) { ; CHECK-LABEL:
>>>>> + at test_06_unsigned( ; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ -1, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nsw i64 [[IV]], 1 ; CHECK-NEXT:
>>>>> +[[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32 ; CHECK-NEXT:
>>>>> +[[CMP:%.*]] = icmp ult i32 [[NARROW_IV]], [[N:%.*]] ; CHECK-NEXT:
>>>>> +br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK:
>>>>> +exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ -1, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ult i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Do not eliminate trunc if it is used by something different 
>>>>> +from
>>>>> icmp.
>>>>> +define void @test_07(i32* %p, i32 %n) { ; CHECK-LABEL: @test_07( 
>>>>> +;
>>>>> +CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32 ;
>>>>> +CHECK-NEXT:    store i32 [[NARROW_IV]], i32* [[P:%.*]] ;
>>>>> +CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[NARROW_IV]], 
>>>>> +[[N:%.*]] ; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP]], label 
>>>>> +[[EXIT:%.*]] ; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  store i32 %narrow.iv, i32* %p
>>>>> +  %cmp = icmp slt i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Check that we can eliminate both signed and unsigned compare.
>>>>> +define void @test_08(i32 %n) {
>>>>> +; CHECK-LABEL: @test_08(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    [[SEXT:%.*]] = sext i32 [[N]] to i64 ; CHECK-NEXT:
>>>>> +br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]] ;
>>>>> +CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[IV]], [[ZEXT]] ;
>>>>> +CHECK-NEXT:    [[CMP:%.*]] = and i1 [[TMP0]], [[TMP1]] ;
>>>>> +CHECK-NEXT:    br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +;
>>>>> +CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp1 = icmp slt i32 %narrow.iv, %n
>>>>> +  %cmp2 = icmp ult i32 %narrow.iv, %n
>>>>> +  %cmp = and i1 %cmp1, %cmp2
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Widen NE as unsigned.
>>>>> +define void @test_09(i32 %n) {
>>>>> +; CHECK-LABEL: @test_09(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i64 [[IV]], [[ZEXT]] ;
>>>>> +CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +; CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %cmp = icmp ne i32 %narrow.iv, %n
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>> +
>>>>> +; Widen NE as signed.
>>>>> +define void @test_10(i32 %n) {
>>>>> +; CHECK-LABEL: @test_10(
>>>>> +; CHECK-NEXT:  entry:
>>>>> +; CHECK-NEXT:    [[SEXT:%.*]] = sext i32 [[N:%.*]] to i64 ;
>>>>> +CHECK-NEXT:    br label [[LOOP:%.*]] ; CHECK:       loop:
>>>>> +; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ -100, [[ENTRY:%.*]] ], [
>>>>> [[IV_NEXT:%.*]], [[LOOP]] ]
>>>>> +; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 ;
>>>>> +CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i64 [[IV]], [[SEXT]] ;
>>>>> +CHECK-NEXT:    [[NEGCMP:%.*]] = icmp slt i64 [[IV]], -10 ;
>>>>> +CHECK-NEXT:    [[CMP:%.*]] = and i1 [[TMP0]], [[NEGCMP]] ;
>>>>> +CHECK-NEXT:    br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]] 
>>>>> +;
>>>>> +CHECK:       exit:
>>>>> +; CHECK-NEXT:    ret void
>>>>> +;
>>>>> +entry:
>>>>> +  br label %loop
>>>>> +loop:
>>>>> +  %iv = phi i64 [ -100, %entry ], [ %iv.next, %loop ]
>>>>> +  %iv.next = add i64 %iv, 1
>>>>> +  %narrow.iv = trunc i64 %iv to i32
>>>>> +  %trunccmp = icmp ne i32 %narrow.iv, %n
>>>>> +  %negcmp = icmp slt i64 %iv, -10
>>>>> +  %cmp = and i1 %trunccmp, %negcmp
>>>>> +  br i1 %cmp, label %loop, label %exit
>>>>> +exit:
>>>>> +  ret void
>>>>> +}
>>>>>
>>>>> Modified:
>>>>> llvm/trunk/test/Transforms/IndVarSimplify/widen-loop-comp.ll
>>>>> URL:
>>>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Ind
>>>>> V
>>>>> ar S
>>>>> implify/widen-loop-comp.ll?rev=335020&r1=335019&r2=335020&view=dif
>>>>> f 
>>>>> ==================================================================
>>>>> =
>>>>> ==
>>>>> =
>>>>> ========
>>>>> --- llvm/trunk/test/Transforms/IndVarSimplify/widen-loop-comp.ll
>>>>> (original)
>>>>> +++ llvm/trunk/test/Transforms/IndVarSimplify/widen-loop-comp.ll
>>>>> +++ Mon Jun 18 21:48:34 2018
>>>>> @@ -332,12 +332,12 @@ define i32 @test10(i32 %v) {
>>>>>        br label %loop
>>>>>       loop:
>>>>> +; CHECK: [[WIDE_V:%[a-z0-9]+]] = sext i32 %v to i64
>>>>>      ; CHECK: loop:
>>>>>      ; CHECK: %indvars.iv = phi i64 [ %indvars.iv.next, %loop ], [ 
>>>>> 0, %entry ]
>>>>>      ; CHECK: %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
>>>>>      ; CHECK: [[MUL:%[a-z0-9]+]] = mul nsw i64 %indvars.iv, -1 -; CHECK:
>>>>> [[MUL_TRUNC:%[a-z0-9]+]] = trunc i64 [[MUL]] to i32 -; CHECK:
>>>>> [[CMP:%[a-z0-9]+]] = icmp eq i32 [[MUL_TRUNC]], %v
>>>>> +; CHECK: [[CMP:%[a-z0-9]+]] = icmp eq i64 [[MUL]], [[WIDE_V]]
>>>>>      ; CHECK: call void @consume.i1(i1 [[CMP]])
>>>>>        %i = phi i32 [ 0, %entry ], [ %i.inc, %loop ]
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> llvm-commits mailing list
>>>>> llvm-commits at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>>>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list