summaryrefslogtreecommitdiffstats
path: root/llvm/test/Transforms/LoopUnroll/rebuild_lcssa.ll
blob: 9de638ce4f8008bac1d51194402f73b769e0843d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
; RUN: opt < %s -loop-unroll -S | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"

; This test shows how unrolling an inner loop could break LCSSA for an outer
; loop, and there is no cheap way to recover it.
;
; In this case the inner loop, L3, is being unrolled. It only runs one
; iteration, so unrolling basically means replacing
;   br i1 true, label %exit, label %L3_header
; with
;   br label %exit
;
; However, this change messes up the loops structure: for instance, block
; L3_body no longer belongs to L2. It becomes an exit block for L2, so LCSSA
; phis for definitions in L2 should now be placed there. In particular, we need
; to insert such a definition for %y1.

; CHECK-LABEL: @foo1
define void @foo1() {
entry:
  br label %L1_header

L1_header:
  br label %L2_header

L2_header:
  %y1 = phi i64 [ undef, %L1_header ], [ %x.lcssa, %L2_latch ]
  br label %L3_header

L3_header:
  %y2 = phi i64 [ 0, %L3_latch ], [ %y1, %L2_header ]
  %x = add i64 undef, -1
  br i1 true, label %L2_latch, label %L3_body

L2_latch:
  %x.lcssa = phi i64 [ %x, %L3_header ]
  br label %L2_header

; CHECK:      L3_body:
; CHECK-NEXT:   %y1.lcssa = phi i64 [ %y1, %L3_header ]
L3_body:
  store i64 %y1, i64* undef
  br i1 false, label %L3_latch, label %L1_latch

L3_latch:
  br i1 true, label %exit, label %L3_header

L1_latch:
  %y.lcssa = phi i64 [ %y2, %L3_body ]
  br label %L1_header

exit:
  ret void
}

; Additional tests for some corner cases.
;
; CHECK-LABEL: @foo2
define void @foo2() {
entry:
  br label %L1_header

L1_header:
  br label %L2_header

L2_header:
  %a = phi i64 [ undef, %L1_header ], [ %dec_us, %L3_header ]
  br label %L3_header

L3_header:
  %b = phi i64 [ 0, %L3_latch ], [ %a, %L2_header ]
  %dec_us = add i64 undef, -1
  br i1 true, label %L2_header, label %L3_break_to_L1

; CHECK:      L3_break_to_L1:
; CHECK-NEXT:   %a.lcssa = phi i64 [ %a, %L3_header ]
L3_break_to_L1:
  br i1 false, label %L3_latch, label %L1_latch

L1_latch:
  %b_lcssa = phi i64 [ %b, %L3_break_to_L1 ]
  br label %L1_header

L3_latch:
  br i1 true, label %Exit, label %L3_header

Exit:
  ret void
}

; CHECK-LABEL: @foo3
define void @foo3() {
entry:
  br label %L1_header

L1_header:
  %a = phi i8* [ %b, %L1_latch ], [ null, %entry ]
  br i1 undef, label %L2_header, label %L1_latch

L2_header:
  br i1 undef, label %L2_latch, label %L1_latch

; CHECK:      L2_latch:
; CHECK-NEXT:   %a.lcssa = phi i8* [ %a, %L2_header ]
L2_latch:
  br i1 true, label %L2_exit, label %L2_header

L1_latch:
  %b = phi i8* [ undef, %L1_header ], [ null, %L2_header ]
  br label %L1_header

L2_exit:
  %a_lcssa1 = phi i8* [ %a, %L2_latch ]
  br label %Exit

Exit:
  %a_lcssa2 = phi i8* [ %a_lcssa1, %L2_exit ]
  ret void
}

; PR26688
; CHECK-LABEL: @foo4
define i8 @foo4() {
entry:
  br label %L1_header

L1_header:
  %x = icmp eq i32 1, 0
  br label %L2_header

L2_header:
  br label %L3_header

L3_header:
  br i1 true, label %L2_header, label %L3_exiting

L3_exiting:
  br i1 true, label %L3_body, label %L1_latch

; CHECK:      L3_body:
; CHECK-NEXT:   %x.lcssa = phi i1
L3_body:
  br i1 %x, label %L3_latch, label %L3_latch

L3_latch:
  br i1 false, label %L3_header, label %exit

L1_latch:
  br label %L1_header

exit:
  ret i8 0
}
OpenPOWER on IntegriCloud