1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -simplifycfg -hoist-common-insts=1 -S < %s                    | FileCheck %s --check-prefixes=HOIST
3; RUN: opt -simplifycfg -hoist-common-insts=0 -S < %s                    | FileCheck %s --check-prefixes=NOHOIST
4; RUN: opt -simplifycfg                       -S < %s                    | FileCheck %s --check-prefixes=NOHOIST,DEFAULT
5
6; This example is produced from a very basic C code:
7;
8;   void f0();
9;   void f1();
10;   void f2();
11;
12;   void loop(int width) {
13;       if(width < 1)
14;           return;
15;       for(int i = 0; i < width - 1; ++i) {
16;           f0();
17;           f1();
18;       }
19;       f0();
20;       f2();
21;   }
22
23; We have a choice here. We can either
24; * hoist the f0() call into loop header,
25;   * which potentially makes loop rotation unprofitable since loop header might
26;     have grown above certain threshold, and such unrotated loops will be
27;     ignored by LoopVectorizer, preventing vectorization
28;   * or loop rotation will succeed, resulting in some weird PHIs that will also
29;     harm vectorization
30; * or not hoist f0() call before performing loop rotation,
31;   at the cost of potential code bloat and/or potentially successfully rotating
32;   the loops, vectorizing them at the cost of compile time.
33
34target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
35
36declare i1 @gen1()
37
38declare void @f0()
39declare void @f1()
40declare void @f2()
41
42declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
43declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
44
45define void @_Z4loopi(i1 %cmp) {
46; HOIST-LABEL: @_Z4loopi(
47; HOIST-NEXT:  entry:
48; HOIST-NEXT:    br i1 [[CMP:%.*]], label [[RETURN:%.*]], label [[FOR_COND:%.*]]
49; HOIST:       for.cond:
50; HOIST-NEXT:    [[CMP1:%.*]] = call i1 @gen1()
51; HOIST-NEXT:    call void @f0()
52; HOIST-NEXT:    br i1 [[CMP1]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
53; HOIST:       for.body:
54; HOIST-NEXT:    call void @f1()
55; HOIST-NEXT:    br label [[FOR_COND]]
56; HOIST:       for.end:
57; HOIST-NEXT:    call void @f2()
58; HOIST-NEXT:    br label [[RETURN]]
59; HOIST:       return:
60; HOIST-NEXT:    ret void
61;
62; NOHOIST-LABEL: @_Z4loopi(
63; NOHOIST-NEXT:  entry:
64; NOHOIST-NEXT:    br i1 [[CMP:%.*]], label [[RETURN:%.*]], label [[FOR_COND:%.*]]
65; NOHOIST:       for.cond:
66; NOHOIST-NEXT:    [[CMP1:%.*]] = call i1 @gen1()
67; NOHOIST-NEXT:    br i1 [[CMP1]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
68; NOHOIST:       for.body:
69; NOHOIST-NEXT:    call void @f0()
70; NOHOIST-NEXT:    call void @f1()
71; NOHOIST-NEXT:    br label [[FOR_COND]]
72; NOHOIST:       for.end:
73; NOHOIST-NEXT:    call void @f0()
74; NOHOIST-NEXT:    call void @f2()
75; NOHOIST-NEXT:    br label [[RETURN]]
76; NOHOIST:       return:
77; NOHOIST-NEXT:    ret void
78;
79entry:
80  br i1 %cmp, label %if.then, label %if.end
81
82if.then:
83  br label %return
84
85if.end:
86  br label %for.cond
87
88for.cond:
89  %cmp1 = call i1 @gen1()
90  br i1 %cmp1, label %for.body, label %for.cond.cleanup
91
92for.cond.cleanup:
93  br label %for.end
94
95for.body:
96  call void @f0()
97  call void @f1()
98  br label %for.inc
99
100for.inc:
101  br label %for.cond
102
103for.end:
104  call void @f0()
105  call void @f2()
106  br label %return
107
108return:
109  ret void
110}
111