[llvm] r335020 - [SimplifyIndVars] Eliminate redundant truncs

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 28 01:37:58 PDT 2018



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/linu
>> 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/Utils/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/IndVar
>>> 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/IndVar
>>> 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/IndVar
>>> S implify/widen-loop-comp.ll?rev=335020&r1=335019&r2=335020&view=diff
>>> =====================================================================
>>> =
>>> ========
>>> --- 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
>>>



More information about the llvm-commits mailing list