Add basic loop fusion pass.

This patch adds a basic loop fusion pass. It will fuse loops that conform to the
following 4 conditions:
  1. Adjacent (no code between them)
  2. Control flow equivalent (if one loop executes, the other loop executes)
  3. Identical bounds (both loops iterate the same number of iterations)
  4. No negative distance dependencies between the loop bodies.

The pass does not make any changes to the IR to create opportunities for fusion.
Instead, it checks if the necessary conditions are met and if so it fuses two
loops together.

The pass has not been added to the pass pipeline yet, and thus is not enabled by
default. It can be run stand alone using the -loop-fusion option.

Differential Revision: https://reviews.llvm.org/D55851

llvm-svn: 358607
This commit is contained in:
Kit Barton 2019-04-17 18:53:27 +00:00
parent a96efb654e
commit 3cdf87940f
13 changed files with 2286 additions and 0 deletions

View File

@ -219,6 +219,7 @@ void initializeLoopDeletionLegacyPassPass(PassRegistry&);
void initializeLoopDistributeLegacyPass(PassRegistry&);
void initializeLoopExtractorPass(PassRegistry&);
void initializeLoopGuardWideningLegacyPassPass(PassRegistry&);
void initializeLoopFuseLegacyPass(PassRegistry&);
void initializeLoopIdiomRecognizeLegacyPassPass(PassRegistry&);
void initializeLoopInfoWrapperPassPass(PassRegistry&);
void initializeLoopInstSimplifyLegacyPassPass(PassRegistry&);

View File

@ -458,6 +458,12 @@ FunctionPass *createNaryReassociatePass();
//
FunctionPass *createLoopDistributePass();
//===----------------------------------------------------------------------===//
//
// LoopFuse - Fuse loops.
//
FunctionPass *createLoopFusePass();
//===----------------------------------------------------------------------===//
//
// LoopLoadElimination - Perform loop-aware load elimination.

View File

@ -0,0 +1,30 @@
//===- LoopFuse.h - Loop Fusion Pass ----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the Loop Fusion pass.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_SCALAR_LOOPFUSE_H
#define LLVM_TRANSFORMS_SCALAR_LOOPFUSE_H
#include "llvm/IR/PassManager.h"
namespace llvm {
class Function;
class LoopFusePass : public PassInfoMixin<LoopFusePass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
} // end namespace llvm
#endif // LLVM_TRANSFORMS_SCALAR_LOOPFUSE_H

View File

@ -122,6 +122,7 @@
#include "llvm/Transforms/Scalar/LoopDataPrefetch.h"
#include "llvm/Transforms/Scalar/LoopDeletion.h"
#include "llvm/Transforms/Scalar/LoopDistribute.h"
#include "llvm/Transforms/Scalar/LoopFuse.h"
#include "llvm/Transforms/Scalar/LoopIdiomRecognize.h"
#include "llvm/Transforms/Scalar/LoopInstSimplify.h"
#include "llvm/Transforms/Scalar/LoopLoadElimination.h"

View File

@ -197,6 +197,7 @@ FUNCTION_PASS("partially-inline-libcalls", PartiallyInlineLibCallsPass())
FUNCTION_PASS("lcssa", LCSSAPass())
FUNCTION_PASS("loop-data-prefetch", LoopDataPrefetchPass())
FUNCTION_PASS("loop-load-elim", LoopLoadEliminationPass())
FUNCTION_PASS("loop-fuse", LoopFusePass())
FUNCTION_PASS("loop-distribute", LoopDistributePass())
FUNCTION_PASS("loop-vectorize", LoopVectorizePass())
FUNCTION_PASS("pgo-memop-opt", PGOMemOPSizeOpt())

View File

@ -28,6 +28,7 @@ add_llvm_library(LLVMScalarOpts
LoopDeletion.cpp
LoopDataPrefetch.cpp
LoopDistribute.cpp
LoopFuse.cpp
LoopIdiomRecognize.cpp
LoopInstSimplify.cpp
LoopInterchange.cpp

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeJumpThreadingPass(Registry);
initializeLegacyLICMPassPass(Registry);
initializeLegacyLoopSinkPassPass(Registry);
initializeLoopFuseLegacyPass(Registry);
initializeLoopDataPrefetchLegacyPassPass(Registry);
initializeLoopDeletionLegacyPassPass(Registry);
initializeLoopAccessLegacyAnalysisPass(Registry);

View File

@ -0,0 +1,371 @@
; RUN: opt -S -loop-fusion -debug-only=loop-fusion -disable-output < %s 2>&1 | FileCheck %s
; REQUIRES: asserts
@B = common global [1024 x i32] zeroinitializer, align 16
; CHECK that the two candidates for fusion are placed into separate candidate
; sets because they are not control flow equivalent.
; CHECK: Performing Loop Fusion on function non_cfe
; CHECK: Fusion Candidates:
; CHECK: *** Fusion Candidate Set ***
; CHECK: bb
; CHECK: ****************************
; CHECK: *** Fusion Candidate Set ***
; CHECK: bb20.preheader
; CHECK: ****************************
; CHECK: Loop Fusion complete
define void @non_cfe(i32* noalias %arg) {
bb:
br label %bb5
bb5: ; preds = %bb14, %bb
%indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb14 ], [ 0, %bb ]
%.01 = phi i32 [ 0, %bb ], [ %tmp15, %bb14 ]
%exitcond4 = icmp ne i64 %indvars.iv2, 100
br i1 %exitcond4, label %bb7, label %bb16
bb7: ; preds = %bb5
%tmp = add nsw i32 %.01, -3
%tmp8 = add nuw nsw i64 %indvars.iv2, 3
%tmp9 = trunc i64 %tmp8 to i32
%tmp10 = mul nsw i32 %tmp, %tmp9
%tmp11 = trunc i64 %indvars.iv2 to i32
%tmp12 = srem i32 %tmp10, %tmp11
%tmp13 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2
store i32 %tmp12, i32* %tmp13, align 4
br label %bb14
bb14: ; preds = %bb7
%indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
%tmp15 = add nuw nsw i32 %.01, 1
br label %bb5
bb16: ; preds = %bb5
%tmp17 = load i32, i32* %arg, align 4
%tmp18 = icmp slt i32 %tmp17, 0
br i1 %tmp18, label %bb20, label %bb33
bb20: ; preds = %bb30, %bb16
%indvars.iv = phi i64 [ %indvars.iv.next, %bb30 ], [ 0, %bb16 ]
%.0 = phi i32 [ 0, %bb16 ], [ %tmp31, %bb30 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb22, label %bb33
bb22: ; preds = %bb20
%tmp23 = add nsw i32 %.0, -3
%tmp24 = add nuw nsw i64 %indvars.iv, 3
%tmp25 = trunc i64 %tmp24 to i32
%tmp26 = mul nsw i32 %tmp23, %tmp25
%tmp27 = trunc i64 %indvars.iv to i32
%tmp28 = srem i32 %tmp26, %tmp27
%tmp29 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv
store i32 %tmp28, i32* %tmp29, align 4
br label %bb30
bb30: ; preds = %bb22
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%tmp31 = add nuw nsw i32 %.0, 1
br label %bb20
bb33: ; preds = %bb20, %bb16
ret void
}
; Check that fusion detects the two canddates are not adjacent (the exit block
; of the first candidate is not the preheader of the second candidate).
; CHECK: Performing Loop Fusion on function non_adjacent
; CHECK: Fusion Candidates:
; CHECK: *** Fusion Candidate Set ***
; CHECK-NEXT: [[LOOP1PREHEADER:bb[0-9]*]]
; CHECK-NEXT: [[LOOP2PREHEADER:bb[0-9]*]]
; CHECK-NEXT: ****************************
; CHECK: Attempting fusion on Candidate Set:
; CHECK-NEXT: [[LOOP1PREHEADER]]
; CHECK-NEXT: [[LOOP2PREHEADER]]
; CHECK: Fusion candidates are not adjacent. Not fusing.
; CHECK: Loop Fusion complete
define void @non_adjacent(i32* noalias %arg) {
bb:
br label %bb3
bb3: ; preds = %bb11, %bb
%.01 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
%exitcond2 = icmp ne i64 %.01, 100
br i1 %exitcond2, label %bb5, label %bb4
bb4: ; preds = %bb3
br label %bb13
bb5: ; preds = %bb3
%tmp = add nsw i64 %.01, -3
%tmp6 = add nuw nsw i64 %.01, 3
%tmp7 = mul nsw i64 %tmp, %tmp6
%tmp8 = srem i64 %tmp7, %.01
%tmp9 = trunc i64 %tmp8 to i32
%tmp10 = getelementptr inbounds i32, i32* %arg, i64 %.01
store i32 %tmp9, i32* %tmp10, align 4
br label %bb11
bb11: ; preds = %bb5
%tmp12 = add nuw nsw i64 %.01, 1
br label %bb3
bb13: ; preds = %bb4
br label %bb14
bb14: ; preds = %bb23, %bb13
%.0 = phi i64 [ 0, %bb13 ], [ %tmp24, %bb23 ]
%exitcond = icmp ne i64 %.0, 100
br i1 %exitcond, label %bb16, label %bb15
bb15: ; preds = %bb14
br label %bb25
bb16: ; preds = %bb14
%tmp17 = add nsw i64 %.0, -3
%tmp18 = add nuw nsw i64 %.0, 3
%tmp19 = mul nsw i64 %tmp17, %tmp18
%tmp20 = srem i64 %tmp19, %.0
%tmp21 = trunc i64 %tmp20 to i32
%tmp22 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %.0
store i32 %tmp21, i32* %tmp22, align 4
br label %bb23
bb23: ; preds = %bb16
%tmp24 = add nuw nsw i64 %.0, 1
br label %bb14
bb25: ; preds = %bb15
ret void
}
; Check that the different bounds are detected and prevent fusion.
; CHECK: Performing Loop Fusion on function different_bounds
; CHECK: Fusion Candidates:
; CHECK: *** Fusion Candidate Set ***
; CHECK-NEXT: [[LOOP1PREHEADER:bb[0-9]*]]
; CHECK-NEXT: [[LOOP2PREHEADER:bb[0-9]*]]
; CHECK-NEXT: ****************************
; CHECK: Attempting fusion on Candidate Set:
; CHECK-NEXT: [[LOOP1PREHEADER]]
; CHECK-NEXT: [[LOOP2PREHEADER]]
; CHECK: Fusion candidates do not have identical trip counts. Not fusing.
; CHECK: Loop Fusion complete
define void @different_bounds(i32* noalias %arg) {
bb:
br label %bb3
bb3: ; preds = %bb11, %bb
%.01 = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ]
%exitcond2 = icmp ne i64 %.01, 100
br i1 %exitcond2, label %bb5, label %bb4
bb4: ; preds = %bb3
br label %bb13
bb5: ; preds = %bb3
%tmp = add nsw i64 %.01, -3
%tmp6 = add nuw nsw i64 %.01, 3
%tmp7 = mul nsw i64 %tmp, %tmp6
%tmp8 = srem i64 %tmp7, %.01
%tmp9 = trunc i64 %tmp8 to i32
%tmp10 = getelementptr inbounds i32, i32* %arg, i64 %.01
store i32 %tmp9, i32* %tmp10, align 4
br label %bb11
bb11: ; preds = %bb5
%tmp12 = add nuw nsw i64 %.01, 1
br label %bb3
bb13: ; preds = %bb4
br label %bb14
bb14: ; preds = %bb23, %bb13
%.0 = phi i64 [ 0, %bb13 ], [ %tmp24, %bb23 ]
%exitcond = icmp ne i64 %.0, 200
br i1 %exitcond, label %bb16, label %bb15
bb15: ; preds = %bb14
br label %bb25
bb16: ; preds = %bb14
%tmp17 = add nsw i64 %.0, -3
%tmp18 = add nuw nsw i64 %.0, 3
%tmp19 = mul nsw i64 %tmp17, %tmp18
%tmp20 = srem i64 %tmp19, %.0
%tmp21 = trunc i64 %tmp20 to i32
%tmp22 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %.0
store i32 %tmp21, i32* %tmp22, align 4
br label %bb23
bb23: ; preds = %bb16
%tmp24 = add nuw nsw i64 %.0, 1
br label %bb14
bb25: ; preds = %bb15
ret void
}
; Check that the negative dependence between the two candidates is identified
; and prevents fusion.
; CHECK: Performing Loop Fusion on function negative_dependence
; CHECK: Fusion Candidates:
; CHECK: *** Fusion Candidate Set ***
; CHECK-NEXT: [[LOOP1PREHEADER:bb[0-9]*]]
; CHECK-NEXT: [[LOOP2PREHEADER:bb[0-9]*]]
; CHECK-NEXT: ****************************
; CHECK: Attempting fusion on Candidate Set:
; CHECK-NEXT: [[LOOP1PREHEADER]]
; CHECK-NEXT: [[LOOP2PREHEADER]]
; CHECK: Memory dependencies do not allow fusion!
; CHECK: Loop Fusion complete
define void @negative_dependence(i32* noalias %arg) {
bb:
br label %bb5
bb5: ; preds = %bb9, %bb
%indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb9 ], [ 0, %bb ]
%exitcond4 = icmp ne i64 %indvars.iv2, 100
br i1 %exitcond4, label %bb7, label %bb11
bb7: ; preds = %bb5
%tmp = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2
%tmp8 = trunc i64 %indvars.iv2 to i32
store i32 %tmp8, i32* %tmp, align 4
br label %bb9
bb9: ; preds = %bb7
%indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
br label %bb5
bb11: ; preds = %bb18, %bb5
%indvars.iv = phi i64 [ %indvars.iv.next, %bb18 ], [ 0, %bb5 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb13, label %bb19
bb13: ; preds = %bb11
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%tmp14 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv.next
%tmp15 = load i32, i32* %tmp14, align 4
%tmp16 = shl nsw i32 %tmp15, 1
%tmp17 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv
store i32 %tmp16, i32* %tmp17, align 4
br label %bb18
bb18: ; preds = %bb13
br label %bb11
bb19: ; preds = %bb11
ret void
}
; Check for values defined in Loop 0 and used in Loop 1.
; It is not safe to fuse in this case, because the second loop has
; a use of %.01.lcssa which is defined in the body of loop 0. The
; first loop must execute completely in order to compute the correct
; value of %.01.lcssa to be used in the second loop.
; CHECK: Performing Loop Fusion on function sumTest
; CHECK: Fusion Candidates:
; CHECK: *** Fusion Candidate Set ***
; CHECK-NEXT: [[LOOP1PREHEADER:bb[0-9]*]]
; CHECK-NEXT: [[LOOP2PREHEADER:bb[0-9]*]]
; CHECK-NEXT: ****************************
; CHECK: Attempting fusion on Candidate Set:
; CHECK-NEXT: [[LOOP1PREHEADER]]
; CHECK-NEXT: [[LOOP2PREHEADER]]
; CHECK: Memory dependencies do not allow fusion!
; CHECK: Loop Fusion complete
define i32 @sumTest(i32* noalias %arg) {
bb:
br label %bb6
bb6: ; preds = %bb9, %bb
%indvars.iv3 = phi i64 [ %indvars.iv.next4, %bb9 ], [ 0, %bb ]
%.01 = phi i32 [ 0, %bb ], [ %tmp11, %bb9 ]
%exitcond5 = icmp ne i64 %indvars.iv3, 100
br i1 %exitcond5, label %bb9, label %bb13
bb9: ; preds = %bb6
%tmp = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv3
%tmp10 = load i32, i32* %tmp, align 4
%tmp11 = add nsw i32 %.01, %tmp10
%indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
br label %bb6
bb13: ; preds = %bb20, %bb6
%.01.lcssa = phi i32 [ %.01, %bb6 ], [ %.01.lcssa, %bb20 ]
%indvars.iv = phi i64 [ %indvars.iv.next, %bb20 ], [ 0, %bb6 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb15, label %bb14
bb14: ; preds = %bb13
br label %bb21
bb15: ; preds = %bb13
%tmp16 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv
%tmp17 = load i32, i32* %tmp16, align 4
%tmp18 = sdiv i32 %tmp17, %.01.lcssa
%tmp19 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv
store i32 %tmp18, i32* %tmp19, align 4
br label %bb20
bb20: ; preds = %bb15
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb13
bb21: ; preds = %bb14
ret i32 %.01.lcssa
}
; Similar to sumTest above. The first loop computes %add and must
; complete before it is used in the second loop. Thus, these two loops
; also cannot be fused.
; CHECK: Performing Loop Fusion on function test
; CHECK: Fusion Candidates:
; CHECK: *** Fusion Candidate Set ***
; CHECK-NEXT: [[LOOP1PREHEADER:for.body[0-9]*.preheader]]
; CHECK-NEXT: [[LOOP2PREHEADER:for.body[0-9]*.preheader]]
; CHECK-NEXT: ****************************
; CHECK: Attempting fusion on Candidate Set:
; CHECK-NEXT: [[LOOP1PREHEADER]]
; CHECK-NEXT: [[LOOP2PREHEADER]]
; CHECK: Memory dependencies do not allow fusion!
; CHECK: Loop Fusion complete
define float @test(float* nocapture %a, i32 %n) {
entry:
%conv = zext i32 %n to i64
%cmp32 = icmp eq i32 %n, 0
br i1 %cmp32, label %for.cond.cleanup7, label %for.body
for.body: ; preds = %for.body, %entry
%i.034 = phi i64 [ %inc, %for.body ], [ 0, %entry ]
%sum1.033 = phi float [ %add, %for.body ], [ 0.000000e+00, %entry ]
%idxprom = trunc i64 %i.034 to i32
%arrayidx = getelementptr inbounds float, float* %a, i32 %idxprom
%0 = load float, float* %arrayidx, align 4
%add = fadd float %sum1.033, %0
%inc = add nuw nsw i64 %i.034, 1
%cmp = icmp ult i64 %inc, %conv
br i1 %cmp, label %for.body, label %for.body8
for.body8: ; preds = %for.body, %for.body8
%i2.031 = phi i64 [ %inc14, %for.body8 ], [ 0, %for.body ]
%idxprom9 = trunc i64 %i2.031 to i32
%arrayidx10 = getelementptr inbounds float, float* %a, i32 %idxprom9
%1 = load float, float* %arrayidx10, align 4
%div = fdiv float %1, %add
store float %div, float* %arrayidx10, align 4
%inc14 = add nuw nsw i64 %i2.031, 1
%cmp5 = icmp ult i64 %inc14, %conv
br i1 %cmp5, label %for.body8, label %for.cond.cleanup7
for.cond.cleanup7: ; preds = %for.body8, %entry
%sum1.0.lcssa36 = phi float [ 0.000000e+00, %entry ], [ %add, %for.body8 ]
ret float %sum1.0.lcssa36
}

View File

@ -0,0 +1,136 @@
; RUN: opt -S -loop-fusion < %s | FileCheck %s
@A = common global [1024 x i32] zeroinitializer, align 16
@B = common global [1024 x i32] zeroinitializer, align 16
@C = common global [1024 x i32] zeroinitializer, align 16
@D = common global [1024 x i32] zeroinitializer, align 16
; CHECK: void @dep_free
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %[[LOOP1HEADER:bb[0-9]+]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %exitcond12, label %[[LOOP1BODY:bb[0-9]+]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]+]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %exitcond9, label %[[LOOP2HEADER:bb[0-9]+]], label %[[LOOP3PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2HEADER]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP3PREHEADER]]
; CHECK: [[LOOP3PREHEADER]]
; CHECK: br i1 %exitcond6, label %[[LOOP3HEADER:bb[0-9]+]], label %[[LOOP4PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP3HEADER]]
; CHECK: br label %[[LOOP3LATCH:bb[0-9]+]]
; CHECK: [[LOOP3LATCH]]
; CHECK: br label %[[LOOP4PREHEADER]]
; CHECK: [[LOOP4PREHEADER]]
; CHECK: br i1 %exitcond, label %[[LOOP4HEADER:bb[0-9]+]], label %[[LOOP4EXIT:bb[0-9]+]]
; CHECK: [[LOOP4EXIT]]
; CHECK: br label %[[FUNCEXIT:bb[0-9]+]]
; CHECK: [[LOOP4HEADER]]
; CHECK: br label %[[LOOP4LATCH:bb[0-9]+]]
; CHECK: [[LOOP4LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: [[FUNCEXIT]]
; CHECK: ret void
define void @dep_free() {
bb:
br label %bb13
bb13: ; preds = %bb22, %bb
%indvars.iv10 = phi i64 [ %indvars.iv.next11, %bb22 ], [ 0, %bb ]
%.0 = phi i32 [ 0, %bb ], [ %tmp23, %bb22 ]
%exitcond12 = icmp ne i64 %indvars.iv10, 100
br i1 %exitcond12, label %bb15, label %bb25
bb15: ; preds = %bb13
%tmp = add nsw i32 %.0, -3
%tmp16 = add nuw nsw i64 %indvars.iv10, 3
%tmp17 = trunc i64 %tmp16 to i32
%tmp18 = mul nsw i32 %tmp, %tmp17
%tmp19 = trunc i64 %indvars.iv10 to i32
%tmp20 = srem i32 %tmp18, %tmp19
%tmp21 = getelementptr inbounds [1024 x i32], [1024 x i32]* @A, i64 0, i64 %indvars.iv10
store i32 %tmp20, i32* %tmp21, align 4
br label %bb22
bb22: ; preds = %bb15
%indvars.iv.next11 = add nuw nsw i64 %indvars.iv10, 1
%tmp23 = add nuw nsw i32 %.0, 1
br label %bb13
bb25: ; preds = %bb35, %bb13
%indvars.iv7 = phi i64 [ %indvars.iv.next8, %bb35 ], [ 0, %bb13 ]
%.01 = phi i32 [ 0, %bb13 ], [ %tmp36, %bb35 ]
%exitcond9 = icmp ne i64 %indvars.iv7, 100
br i1 %exitcond9, label %bb27, label %bb38
bb27: ; preds = %bb25
%tmp28 = add nsw i32 %.01, -3
%tmp29 = add nuw nsw i64 %indvars.iv7, 3
%tmp30 = trunc i64 %tmp29 to i32
%tmp31 = mul nsw i32 %tmp28, %tmp30
%tmp32 = trunc i64 %indvars.iv7 to i32
%tmp33 = srem i32 %tmp31, %tmp32
%tmp34 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv7
store i32 %tmp33, i32* %tmp34, align 4
br label %bb35
bb35: ; preds = %bb27
%indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1
%tmp36 = add nuw nsw i32 %.01, 1
br label %bb25
bb38: ; preds = %bb48, %bb25
%indvars.iv4 = phi i64 [ %indvars.iv.next5, %bb48 ], [ 0, %bb25 ]
%.02 = phi i32 [ 0, %bb25 ], [ %tmp49, %bb48 ]
%exitcond6 = icmp ne i64 %indvars.iv4, 100
br i1 %exitcond6, label %bb40, label %bb51
bb40: ; preds = %bb38
%tmp41 = add nsw i32 %.02, -3
%tmp42 = add nuw nsw i64 %indvars.iv4, 3
%tmp43 = trunc i64 %tmp42 to i32
%tmp44 = mul nsw i32 %tmp41, %tmp43
%tmp45 = trunc i64 %indvars.iv4 to i32
%tmp46 = srem i32 %tmp44, %tmp45
%tmp47 = getelementptr inbounds [1024 x i32], [1024 x i32]* @C, i64 0, i64 %indvars.iv4
store i32 %tmp46, i32* %tmp47, align 4
br label %bb48
bb48: ; preds = %bb40
%indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
%tmp49 = add nuw nsw i32 %.02, 1
br label %bb38
bb51: ; preds = %bb61, %bb38
%indvars.iv = phi i64 [ %indvars.iv.next, %bb61 ], [ 0, %bb38 ]
%.03 = phi i32 [ 0, %bb38 ], [ %tmp62, %bb61 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb53, label %bb52
bb52: ; preds = %bb51
br label %bb63
bb53: ; preds = %bb51
%tmp54 = add nsw i32 %.03, -3
%tmp55 = add nuw nsw i64 %indvars.iv, 3
%tmp56 = trunc i64 %tmp55 to i32
%tmp57 = mul nsw i32 %tmp54, %tmp56
%tmp58 = trunc i64 %indvars.iv to i32
%tmp59 = srem i32 %tmp57, %tmp58
%tmp60 = getelementptr inbounds [1024 x i32], [1024 x i32]* @D, i64 0, i64 %indvars.iv
store i32 %tmp59, i32* %tmp60, align 4
br label %bb61
bb61: ; preds = %bb53
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%tmp62 = add nuw nsw i32 %.03, 1
br label %bb51
bb63: ; preds = %bb52
ret void
}

View File

@ -0,0 +1,86 @@
; RUN: opt -S -loop-fusion < %s 2>&1 | FileCheck %s
@A = common global [1024 x [1024 x i32]] zeroinitializer, align 16
@B = common global [1024 x [1024 x i32]] zeroinitializer, align 16
; CHECK: void @dep_free
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %[[LOOP1HEADER:bb[0-9]*]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP1BODY:bb[0-9]*]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]*]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP2BODY:bb[0-9]*]], label %[[LOOP2EXIT:bb[0-9]*]]
; CHECK: [[LOOP2BODY]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: ret void
define void @dep_free() {
bb:
br label %bb9
bb9: ; preds = %bb35, %bb
%indvars.iv6 = phi i64 [ %indvars.iv.next7, %bb35 ], [ 0, %bb ]
%.0 = phi i32 [ 0, %bb ], [ %tmp36, %bb35 ]
%exitcond8 = icmp ne i64 %indvars.iv6, 100
br i1 %exitcond8, label %bb11, label %bb10
bb10: ; preds = %bb9
br label %bb37
bb11: ; preds = %bb9
br label %bb12
bb12: ; preds = %bb21, %bb11
%indvars.iv = phi i64 [ %indvars.iv.next, %bb21 ], [ 0, %bb11 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb14, label %bb23
bb14: ; preds = %bb12
%tmp = add nsw i32 %.0, -3
%tmp15 = add nuw nsw i64 %indvars.iv6, 3
%tmp16 = trunc i64 %tmp15 to i32
%tmp17 = mul nsw i32 %tmp, %tmp16
%tmp18 = trunc i64 %indvars.iv6 to i32
%tmp19 = srem i32 %tmp17, %tmp18
%tmp20 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @A, i64 0, i64 %indvars.iv6, i64 %indvars.iv
store i32 %tmp19, i32* %tmp20, align 4
br label %bb21
bb21: ; preds = %bb14
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb12
bb23: ; preds = %bb33, %bb12
%indvars.iv3 = phi i64 [ %indvars.iv.next4, %bb33 ], [ 0, %bb12 ]
%exitcond5 = icmp ne i64 %indvars.iv3, 100
br i1 %exitcond5, label %bb25, label %bb35
bb25: ; preds = %bb23
%tmp26 = add nsw i32 %.0, -3
%tmp27 = add nuw nsw i64 %indvars.iv6, 3
%tmp28 = trunc i64 %tmp27 to i32
%tmp29 = mul nsw i32 %tmp26, %tmp28
%tmp30 = trunc i64 %indvars.iv6 to i32
%tmp31 = srem i32 %tmp29, %tmp30
%tmp32 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @B, i64 0, i64 %indvars.iv6, i64 %indvars.iv3
store i32 %tmp31, i32* %tmp32, align 4
br label %bb33
bb33: ; preds = %bb25
%indvars.iv.next4 = add nuw nsw i64 %indvars.iv3, 1
br label %bb23
bb35: ; preds = %bb23
%indvars.iv.next7 = add nuw nsw i64 %indvars.iv6, 1
%tmp36 = add nuw nsw i32 %.0, 1
br label %bb9
bb37: ; preds = %bb10
ret void
}

View File

@ -0,0 +1,120 @@
; RUN: opt -S -loop-fusion < %s | FileCheck %s
;
; int A[1024][1024];
; int B[1024][1024];
;
; #define EXPENSIVE_PURE_COMPUTATION(i) ((i - 3) * (i + 3) % i)
;
; void dep_free() {
;
; for (int i = 0; i < 100; i++)
; for (int j = 0; j < 100; j++)
; A[i][j] = EXPENSIVE_PURE_COMPUTATION(i);
;
; for (int i = 0; i < 100; i++)
; for (int j = 0; j < 100; j++)
; B[i][j] = EXPENSIVE_PURE_COMPUTATION(i);
; }
;
@A = common global [1024 x [1024 x i32]] zeroinitializer, align 16
@B = common global [1024 x [1024 x i32]] zeroinitializer, align 16
; CHECK: void @dep_free
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %[[LOOP1HEADER:bb[0-9]+]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %exitcond12, label %[[LOOP3PREHEADER:bb[0-9]+.preheader]], label %[[LOOP2HEADER:bb[0-9]+]]
; CHECK: [[LOOP3PREHEADER]]
; CHECK: br label %[[LOOP3HEADER:bb[0-9]+]]
; CHECK: [[LOOP3HEADER]]
; CHECK: br i1 %exitcond9, label %[[LOOP3BODY:bb[0-9]+]], label %[[LOOP1LATCH:bb[0-9]+]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2HEADER:bb[0-9]+]]
; CHECK: [[LOOP2HEADER]]
; CHECK: br i1 %exitcond6, label %[[LOOP4PREHEADER:bb[0-9]+.preheader]], label %[[LOOP2EXITBLOCK:bb[0-9]+]]
; CHECK: [[LOOP4PREHEADER]]
; CHECK: br label %[[LOOP4HEADER:bb[0-9]+]]
; CHECK: [[LOOP2EXITBLOCK]]
; CHECK-NEXT: br label %[[FUNCEXIT:bb[0-9]+]]
; CHECK: [[LOOP4HEADER]]
; CHECK: br i1 %exitcond, label %[[LOOP4BODY:bb[0-9]+]], label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER:bb[0-9]+]]
; CHECK: [[FUNCEXIT]]
; CHECK: ret void
; TODO: The current version of loop fusion does not allow the inner loops to be
; fused because they are not control flow equivalent and adjacent. These are
; limitations that can be addressed in future improvements to fusion.
define void @dep_free() {
bb:
br label %bb13
bb13: ; preds = %bb27, %bb
%indvars.iv10 = phi i64 [ %indvars.iv.next11, %bb27 ], [ 0, %bb ]
%.0 = phi i32 [ 0, %bb ], [ %tmp28, %bb27 ]
%exitcond12 = icmp ne i64 %indvars.iv10, 100
br i1 %exitcond12, label %bb16, label %bb30
bb16: ; preds = %bb25, %bb13
%indvars.iv7 = phi i64 [ %indvars.iv.next8, %bb25 ], [ 0, %bb13 ]
%exitcond9 = icmp ne i64 %indvars.iv7, 100
br i1 %exitcond9, label %bb18, label %bb27
bb18: ; preds = %bb16
%tmp = add nsw i32 %.0, -3
%tmp19 = add nuw nsw i64 %indvars.iv10, 3
%tmp20 = trunc i64 %tmp19 to i32
%tmp21 = mul nsw i32 %tmp, %tmp20
%tmp22 = trunc i64 %indvars.iv10 to i32
%tmp23 = srem i32 %tmp21, %tmp22
%tmp24 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @A, i64 0, i64 %indvars.iv10, i64 %indvars.iv7
store i32 %tmp23, i32* %tmp24, align 4
br label %bb25
bb25: ; preds = %bb18
%indvars.iv.next8 = add nuw nsw i64 %indvars.iv7, 1
br label %bb16
bb27: ; preds = %bb16
%indvars.iv.next11 = add nuw nsw i64 %indvars.iv10, 1
%tmp28 = add nuw nsw i32 %.0, 1
br label %bb13
bb30: ; preds = %bb45, %bb13
%indvars.iv4 = phi i64 [ %indvars.iv.next5, %bb45 ], [ 0, %bb13 ]
%.02 = phi i32 [ 0, %bb13 ], [ %tmp46, %bb45 ]
%exitcond6 = icmp ne i64 %indvars.iv4, 100
br i1 %exitcond6, label %bb33, label %bb31
bb31: ; preds = %bb30
br label %bb47
bb33: ; preds = %bb43, %bb30
%indvars.iv = phi i64 [ %indvars.iv.next, %bb43 ], [ 0, %bb30 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb35, label %bb45
bb35: ; preds = %bb33
%tmp36 = add nsw i32 %.02, -3
%tmp37 = add nuw nsw i64 %indvars.iv4, 3
%tmp38 = trunc i64 %tmp37 to i32
%tmp39 = mul nsw i32 %tmp36, %tmp38
%tmp40 = trunc i64 %indvars.iv4 to i32
%tmp41 = srem i32 %tmp39, %tmp40
%tmp42 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @B, i64 0, i64 %indvars.iv4, i64 %indvars.iv
store i32 %tmp41, i32* %tmp42, align 4
br label %bb43
bb43: ; preds = %bb35
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb33
bb45: ; preds = %bb33
%indvars.iv.next5 = add nuw nsw i64 %indvars.iv4, 1
%tmp46 = add nuw nsw i32 %.02, 1
br label %bb30
bb47: ; preds = %bb31
ret void
}

View File

@ -0,0 +1,317 @@
; RUN: opt -S -loop-fusion < %s | FileCheck %s
@B = common global [1024 x i32] zeroinitializer, align 16
; CHECK: void @dep_free
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %[[LOOP1HEADER:bb[0-9]*]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP1BODY:bb[0-9]*]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]*]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP2BODY:bb[0-9]*]], label %[[LOOP2EXIT:bb[0-9]*]]
; CHECK: [[LOOP2BODY]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: ret void
define void @dep_free(i32* noalias %arg) {
bb:
br label %bb5
bb5: ; preds = %bb14, %bb
%indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb14 ], [ 0, %bb ]
%.01 = phi i32 [ 0, %bb ], [ %tmp15, %bb14 ]
%exitcond4 = icmp ne i64 %indvars.iv2, 100
br i1 %exitcond4, label %bb7, label %bb17
bb7: ; preds = %bb5
%tmp = add nsw i32 %.01, -3
%tmp8 = add nuw nsw i64 %indvars.iv2, 3
%tmp9 = trunc i64 %tmp8 to i32
%tmp10 = mul nsw i32 %tmp, %tmp9
%tmp11 = trunc i64 %indvars.iv2 to i32
%tmp12 = srem i32 %tmp10, %tmp11
%tmp13 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2
store i32 %tmp12, i32* %tmp13, align 4
br label %bb14
bb14: ; preds = %bb7
%indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
%tmp15 = add nuw nsw i32 %.01, 1
br label %bb5
bb17: ; preds = %bb27, %bb5
%indvars.iv = phi i64 [ %indvars.iv.next, %bb27 ], [ 0, %bb5 ]
%.0 = phi i32 [ 0, %bb5 ], [ %tmp28, %bb27 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb19, label %bb18
bb18: ; preds = %bb17
br label %bb29
bb19: ; preds = %bb17
%tmp20 = add nsw i32 %.0, -3
%tmp21 = add nuw nsw i64 %indvars.iv, 3
%tmp22 = trunc i64 %tmp21 to i32
%tmp23 = mul nsw i32 %tmp20, %tmp22
%tmp24 = trunc i64 %indvars.iv to i32
%tmp25 = srem i32 %tmp23, %tmp24
%tmp26 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv
store i32 %tmp25, i32* %tmp26, align 4
br label %bb27
bb27: ; preds = %bb19
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%tmp28 = add nuw nsw i32 %.0, 1
br label %bb17
bb29: ; preds = %bb18
ret void
}
; CHECK: void @dep_free_parametric
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %[[LOOP1HEADER:bb[0-9]*]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP1BODY:bb[0-9]*]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]*]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP2BODY:bb[0-9]*]], label %[[LOOP2EXIT:bb[0-9]*]]
; CHECK: [[LOOP2BODY]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: ret void
define void @dep_free_parametric(i32* noalias %arg, i64 %arg2) {
bb:
br label %bb3
bb3: ; preds = %bb12, %bb
%.01 = phi i64 [ 0, %bb ], [ %tmp13, %bb12 ]
%tmp = icmp slt i64 %.01, %arg2
br i1 %tmp, label %bb5, label %bb15
bb5: ; preds = %bb3
%tmp6 = add nsw i64 %.01, -3
%tmp7 = add nuw nsw i64 %.01, 3
%tmp8 = mul nsw i64 %tmp6, %tmp7
%tmp9 = srem i64 %tmp8, %.01
%tmp10 = trunc i64 %tmp9 to i32
%tmp11 = getelementptr inbounds i32, i32* %arg, i64 %.01
store i32 %tmp10, i32* %tmp11, align 4
br label %bb12
bb12: ; preds = %bb5
%tmp13 = add nuw nsw i64 %.01, 1
br label %bb3
bb15: ; preds = %bb25, %bb3
%.0 = phi i64 [ 0, %bb3 ], [ %tmp26, %bb25 ]
%tmp16 = icmp slt i64 %.0, %arg2
br i1 %tmp16, label %bb18, label %bb17
bb17: ; preds = %bb15
br label %bb27
bb18: ; preds = %bb15
%tmp19 = add nsw i64 %.0, -3
%tmp20 = add nuw nsw i64 %.0, 3
%tmp21 = mul nsw i64 %tmp19, %tmp20
%tmp22 = srem i64 %tmp21, %.0
%tmp23 = trunc i64 %tmp22 to i32
%tmp24 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %.0
store i32 %tmp23, i32* %tmp24, align 4
br label %bb25
bb25: ; preds = %bb18
%tmp26 = add nuw nsw i64 %.0, 1
br label %bb15
bb27: ; preds = %bb17
ret void
}
; CHECK: void @raw_only
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %[[LOOP1HEADER:bb[0-9]*]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP1BODY:bb[0-9]*]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]*]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP2BODY:bb[0-9]*]], label %[[LOOP2EXIT:bb[0-9]*]]
; CHECK: [[LOOP2BODY]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: ret void
define void @raw_only(i32* noalias %arg) {
bb:
br label %bb5
bb5: ; preds = %bb9, %bb
%indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb9 ], [ 0, %bb ]
%exitcond4 = icmp ne i64 %indvars.iv2, 100
br i1 %exitcond4, label %bb7, label %bb11
bb7: ; preds = %bb5
%tmp = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2
%tmp8 = trunc i64 %indvars.iv2 to i32
store i32 %tmp8, i32* %tmp, align 4
br label %bb9
bb9: ; preds = %bb7
%indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
br label %bb5
bb11: ; preds = %bb18, %bb5
%indvars.iv = phi i64 [ %indvars.iv.next, %bb18 ], [ 0, %bb5 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb13, label %bb19
bb13: ; preds = %bb11
%tmp14 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv
%tmp15 = load i32, i32* %tmp14, align 4
%tmp16 = shl nsw i32 %tmp15, 1
%tmp17 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv
store i32 %tmp16, i32* %tmp17, align 4
br label %bb18
bb18: ; preds = %bb13
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb11
bb19: ; preds = %bb11
ret void
}
; CHECK: void @raw_only_parametric
; CHECK-NEXT: bb:
; CHECK: br label %[[LOOP1HEADER:bb[0-9]*]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP1BODY:bb[0-9]*]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]*]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP2BODY:bb[0-9]*]], label %[[LOOP2EXIT:bb[0-9]*]]
; CHECK: [[LOOP2BODY]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: ret void
define void @raw_only_parametric(i32* noalias %arg, i32 %arg4) {
bb:
br label %bb5
bb5: ; preds = %bb11, %bb
%indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb11 ], [ 0, %bb ]
%tmp = sext i32 %arg4 to i64
%tmp6 = icmp slt i64 %indvars.iv2, %tmp
br i1 %tmp6, label %bb8, label %bb14
bb8: ; preds = %bb5
%tmp9 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2
%tmp10 = trunc i64 %indvars.iv2 to i32
store i32 %tmp10, i32* %tmp9, align 4
br label %bb11
bb11: ; preds = %bb8
%indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
br label %bb5
bb14: ; preds = %bb22, %bb5
%indvars.iv = phi i64 [ %indvars.iv.next, %bb22 ], [ 0, %bb5 ]
%tmp13 = sext i32 %arg4 to i64
%tmp15 = icmp slt i64 %indvars.iv, %tmp13
br i1 %tmp15, label %bb17, label %bb23
bb17: ; preds = %bb14
%tmp18 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv
%tmp19 = load i32, i32* %tmp18, align 4
%tmp20 = shl nsw i32 %tmp19, 1
%tmp21 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv
store i32 %tmp20, i32* %tmp21, align 4
br label %bb22
bb22: ; preds = %bb17
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb14
bb23: ; preds = %bb14
ret void
}
; CHECK: void @forward_dep
; CHECK-NEXT: bb:
; CHECK: br label %[[LOOP1HEADER:bb[0-9]*]]
; CHECK: [[LOOP1HEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP1BODY:bb[0-9]*]], label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP1BODY]]
; CHECK: br label %[[LOOP1LATCH:bb[0-9]*]]
; CHECK: [[LOOP1LATCH]]
; CHECK: br label %[[LOOP2PREHEADER:bb[0-9]+]]
; CHECK: [[LOOP2PREHEADER]]
; CHECK: br i1 %{{.*}}, label %[[LOOP2BODY:bb[0-9]*]], label %[[LOOP2EXIT:bb[0-9]*]]
; CHECK: [[LOOP2BODY]]
; CHECK: br label %[[LOOP2LATCH:bb[0-9]+]]
; CHECK: [[LOOP2LATCH]]
; CHECK: br label %[[LOOP1HEADER]]
; CHECK: ret void
define void @forward_dep(i32* noalias %arg) {
bb:
br label %bb5
bb5: ; preds = %bb14, %bb
%indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb14 ], [ 0, %bb ]
%.01 = phi i32 [ 0, %bb ], [ %tmp15, %bb14 ]
%exitcond4 = icmp ne i64 %indvars.iv2, 100
br i1 %exitcond4, label %bb7, label %bb17
bb7: ; preds = %bb5
%tmp = add nsw i32 %.01, -3
%tmp8 = add nuw nsw i64 %indvars.iv2, 3
%tmp9 = trunc i64 %tmp8 to i32
%tmp10 = mul nsw i32 %tmp, %tmp9
%tmp11 = trunc i64 %indvars.iv2 to i32
%tmp12 = srem i32 %tmp10, %tmp11
%tmp13 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2
store i32 %tmp12, i32* %tmp13, align 4
br label %bb14
bb14: ; preds = %bb7
%indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1
%tmp15 = add nuw nsw i32 %.01, 1
br label %bb5
bb17: ; preds = %bb25, %bb5
%indvars.iv = phi i64 [ %indvars.iv.next, %bb25 ], [ 0, %bb5 ]
%exitcond = icmp ne i64 %indvars.iv, 100
br i1 %exitcond, label %bb19, label %bb26
bb19: ; preds = %bb17
%tmp20 = add nsw i64 %indvars.iv, -3
%tmp21 = getelementptr inbounds i32, i32* %arg, i64 %tmp20
%tmp22 = load i32, i32* %tmp21, align 4
%tmp23 = mul nsw i32 %tmp22, 3
%tmp24 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv
store i32 %tmp23, i32* %tmp24, align 4
br label %bb25
bb25: ; preds = %bb19
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
br label %bb17
bb26: ; preds = %bb17
ret void
}