xref: /llvm-project/flang/test/Lower/do_loop_unstructured.f90 (revision a88677edc0792534ba3157bf7d7a1b98e470f2fb)
1! RUN: bbc -emit-fir -hlfir=false -o - %s | FileCheck %s
2! RUN: %flang_fc1 -emit-fir -flang-deprecated-no-hlfir -o - %s | FileCheck %s
3! RUN: %flang_fc1 -emit-fir -flang-deprecated-no-hlfir -fwrapv -o - %s | FileCheck %s --check-prefix=NO-NSW
4
5! Tests for unstructured loops.
6
7! NO-NSW-NOT: overflow<nsw>
8
9! Test a simple unstructured loop. Test for the existence of,
10! -> The initialization of the trip-count and loop-variable
11! -> The branch to the body or the exit inside the header
12! -> The increment of the trip-count and the loop-variable inside the body
13subroutine simple_unstructured()
14  integer :: i
15  do i=1,100
16    goto 404
17    404 continue
18  end do
19end subroutine
20! CHECK-LABEL: simple_unstructured
21! CHECK:   %[[TRIP_VAR_REF:.*]] = fir.alloca i32
22! CHECK:   %[[LOOP_VAR_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_unstructuredEi"}
23! CHECK:   %[[ONE:.*]] = arith.constant 1 : i32
24! CHECK:   %[[HUNDRED:.*]] = arith.constant 100 : i32
25! CHECK:   %[[STEP_ONE:.*]] = arith.constant 1 : i32
26! CHECK:   %[[TMP1:.*]] = arith.subi %[[HUNDRED]], %[[ONE]] : i32
27! CHECK:   %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[STEP_ONE]] : i32
28! CHECK:   %[[TRIP_COUNT:.*]] = arith.divsi %[[TMP2]], %[[STEP_ONE]] : i32
29! CHECK:   fir.store %[[TRIP_COUNT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
30! CHECK:   fir.store %[[ONE]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
31! CHECK:   cf.br ^[[HEADER:.*]]
32! CHECK: ^[[HEADER]]:
33! CHECK:   %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
34! CHECK:   %[[ZERO:.*]] = arith.constant 0 : i32
35! CHECK:   %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
36! CHECK:   cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
37! CHECK: ^[[BODY]]:
38! CHECK:   %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
39! CHECK:   %[[ONE_1:.*]] = arith.constant 1 : i32
40! CHECK:   %[[TRIP_VAR_NEXT:.*]] = arith.subi %[[TRIP_VAR]], %[[ONE_1]] : i32
41! CHECK:   fir.store %[[TRIP_VAR_NEXT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
42! CHECK:   %[[LOOP_VAR:.*]] = fir.load %[[LOOP_VAR_REF]] : !fir.ref<i32>
43! CHECK:   %[[STEP_ONE_2:.*]] = arith.constant 1 : i32
44! CHECK:   %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_ONE_2]] overflow<nsw> : i32
45! CHECK:   fir.store %[[LOOP_VAR_NEXT]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
46! CHECK:   cf.br ^[[HEADER]]
47! CHECK: ^[[EXIT]]:
48! CHECK:   return
49
50! Test an unstructured loop with a step. Mostly similar to the previous one.
51! Only difference is a non-unit step.
52subroutine simple_unstructured_with_step()
53  integer :: i
54  do i=1,100,2
55    goto 404
56    404 continue
57  end do
58end subroutine
59! CHECK-LABEL: simple_unstructured_with_step
60! CHECK:   %[[TRIP_VAR_REF:.*]] = fir.alloca i32
61! CHECK:   %[[LOOP_VAR_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_unstructured_with_stepEi"}
62! CHECK:   %[[ONE:.*]] = arith.constant 1 : i32
63! CHECK:   %[[HUNDRED:.*]] = arith.constant 100 : i32
64! CHECK:   %[[STEP:.*]] = arith.constant 2 : i32
65! CHECK:   %[[TMP1:.*]] = arith.subi %[[HUNDRED]], %[[ONE]] : i32
66! CHECK:   %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[STEP]] : i32
67! CHECK:   %[[TRIP_COUNT:.*]] = arith.divsi %[[TMP2]], %[[STEP]] : i32
68! CHECK:   fir.store %[[TRIP_COUNT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
69! CHECK:   fir.store %[[ONE]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
70! CHECK:   cf.br ^[[HEADER:.*]]
71! CHECK: ^[[HEADER]]:
72! CHECK:   %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
73! CHECK:   %[[ZERO:.*]] = arith.constant 0 : i32
74! CHECK:   %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
75! CHECK:   cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
76! CHECK: ^[[BODY]]:
77! CHECK:   %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_REF]] : !fir.ref<i32>
78! CHECK:   %[[ONE_1:.*]] = arith.constant 1 : i32
79! CHECK:   %[[TRIP_VAR_NEXT:.*]] = arith.subi %[[TRIP_VAR]], %[[ONE_1]] : i32
80! CHECK:   fir.store %[[TRIP_VAR_NEXT]] to %[[TRIP_VAR_REF]] : !fir.ref<i32>
81! CHECK:   %[[LOOP_VAR:.*]] = fir.load %[[LOOP_VAR_REF]] : !fir.ref<i32>
82! CHECK:   %[[STEP_2:.*]] = arith.constant 2 : i32
83! CHECK:   %[[LOOP_VAR_NEXT:.*]] = arith.addi %[[LOOP_VAR]], %[[STEP_2]] overflow<nsw> : i32
84! CHECK:   fir.store %[[LOOP_VAR_NEXT]] to %[[LOOP_VAR_REF]] : !fir.ref<i32>
85! CHECK:   cf.br ^[[HEADER]]
86! CHECK: ^[[EXIT]]:
87! CHECK:   return
88
89! Test a three nested unstructured loop. Three nesting is the basic case where
90! we have loops that are neither innermost or outermost.
91subroutine nested_unstructured()
92  integer :: i, j, k
93  do i=1,100
94    do j=1,200
95      do k=1,300
96        goto 404
97        404 continue
98      end do
99    end do
100  end do
101end subroutine
102! CHECK-LABEL: nested_unstructured
103! CHECK:   %[[TRIP_VAR_K_REF:.*]] = fir.alloca i32
104! CHECK:   %[[TRIP_VAR_J_REF:.*]] = fir.alloca i32
105! CHECK:   %[[TRIP_VAR_I_REF:.*]] = fir.alloca i32
106! CHECK:   %[[LOOP_VAR_I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_unstructuredEi"}
107! CHECK:   %[[LOOP_VAR_J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_unstructuredEj"}
108! CHECK:   %[[LOOP_VAR_K_REF:.*]] = fir.alloca i32 {bindc_name = "k", uniq_name = "_QFnested_unstructuredEk"}
109! CHECK:   %[[I_START:.*]] = arith.constant 1 : i32
110! CHECK:   %[[I_END:.*]] = arith.constant 100 : i32
111! CHECK:   %[[I_STEP:.*]] = arith.constant 1 : i32
112! CHECK:   %[[TMP1:.*]] = arith.subi %[[I_END]], %[[I_START]] : i32
113! CHECK:   %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[I_STEP]] : i32
114! CHECK:   %[[TRIP_COUNT_I:.*]] = arith.divsi %[[TMP2]], %[[I_STEP]] : i32
115! CHECK:   fir.store %[[TRIP_COUNT_I]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
116! CHECK:   fir.store %[[I_START]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
117! CHECK:   cf.br ^[[HEADER_I:.*]]
118! CHECK: ^[[HEADER_I]]:
119! CHECK:   %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
120! CHECK:   %[[ZERO_1:.*]] = arith.constant 0 : i32
121! CHECK:   %[[COND_I:.*]] = arith.cmpi sgt, %[[TRIP_VAR_I]], %[[ZERO_1]] : i32
122! CHECK:   cf.cond_br %[[COND_I]], ^[[BODY_I:.*]], ^[[EXIT_I:.*]]
123! CHECK: ^[[BODY_I]]:
124! CHECK:   %[[J_START:.*]] = arith.constant 1 : i32
125! CHECK:   %[[J_END:.*]] = arith.constant 200 : i32
126! CHECK:   %[[J_STEP:.*]] = arith.constant 1 : i32
127! CHECK:   %[[TMP3:.*]] = arith.subi %[[J_END]], %[[J_START]] : i32
128! CHECK:   %[[TMP4:.*]] = arith.addi %[[TMP3]], %[[J_STEP]] : i32
129! CHECK:   %[[TRIP_COUNT_J:.*]] = arith.divsi %[[TMP4]], %[[J_STEP]] : i32
130! CHECK:   fir.store %[[TRIP_COUNT_J]] to %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
131! CHECK:   fir.store %[[J_START]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
132! CHECK:   cf.br ^[[HEADER_J:.*]]
133! CHECK: ^[[HEADER_J]]:
134! CHECK:   %[[TRIP_VAR_J:.*]] = fir.load %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
135! CHECK:   %[[ZERO_2:.*]] = arith.constant 0 : i32
136! CHECK:   %[[COND_J:.*]] = arith.cmpi sgt, %[[TRIP_VAR_J]], %[[ZERO_2]] : i32
137! CHECK:   cf.cond_br %[[COND_J]], ^[[BODY_J:.*]], ^[[EXIT_J:.*]]
138! CHECK: ^[[BODY_J]]:
139! CHECK:   %[[K_START:.*]] = arith.constant 1 : i32
140! CHECK:   %[[K_END:.*]] = arith.constant 300 : i32
141! CHECK:   %[[K_STEP:.*]] = arith.constant 1 : i32
142! CHECK:   %[[TMP3:.*]] = arith.subi %[[K_END]], %[[K_START]] : i32
143! CHECK:   %[[TMP4:.*]] = arith.addi %[[TMP3]], %[[K_STEP]] : i32
144! CHECK:   %[[TRIP_COUNT_K:.*]] = arith.divsi %[[TMP4]], %[[K_STEP]] : i32
145! CHECK:   fir.store %[[TRIP_COUNT_K]] to %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
146! CHECK:   fir.store %[[K_START]] to %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
147! CHECK:   cf.br ^[[HEADER_K:.*]]
148! CHECK: ^[[HEADER_K]]:
149! CHECK:   %[[TRIP_VAR_K:.*]] = fir.load %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
150! CHECK:   %[[ZERO_2:.*]] = arith.constant 0 : i32
151! CHECK:   %[[COND_K:.*]] = arith.cmpi sgt, %[[TRIP_VAR_K]], %[[ZERO_2]] : i32
152! CHECK:   cf.cond_br %[[COND_K]], ^[[BODY_K:.*]], ^[[EXIT_K:.*]]
153! CHECK: ^[[BODY_K]]:
154! CHECK:   %[[TRIP_VAR_K:.*]] = fir.load %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
155! CHECK:   %[[ONE_1:.*]] = arith.constant 1 : i32
156! CHECK:   %[[TRIP_VAR_K_NEXT:.*]] = arith.subi %[[TRIP_VAR_K]], %[[ONE_1]] : i32
157! CHECK:   fir.store %[[TRIP_VAR_K_NEXT]] to %[[TRIP_VAR_K_REF]] : !fir.ref<i32>
158! CHECK:   %[[LOOP_VAR_K:.*]] = fir.load %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
159! CHECK:   %[[K_STEP_2:.*]] = arith.constant 1 : i32
160! CHECK:   %[[LOOP_VAR_K_NEXT:.*]] = arith.addi %[[LOOP_VAR_K]], %[[K_STEP_2]] overflow<nsw> : i32
161! CHECK:   fir.store %[[LOOP_VAR_K_NEXT]] to %[[LOOP_VAR_K_REF]] : !fir.ref<i32>
162! CHECK:   cf.br ^[[HEADER_K]]
163! CHECK: ^[[EXIT_K]]:
164! CHECK:   %[[TRIP_VAR_J:.*]] = fir.load %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
165! CHECK:   %[[ONE_1:.*]] = arith.constant 1 : i32
166! CHECK:   %[[TRIP_VAR_J_NEXT:.*]] = arith.subi %[[TRIP_VAR_J]], %[[ONE_1]] : i32
167! CHECK:   fir.store %[[TRIP_VAR_J_NEXT]] to %[[TRIP_VAR_J_REF]] : !fir.ref<i32>
168! CHECK:   %[[LOOP_VAR_J:.*]] = fir.load %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
169! CHECK:   %[[J_STEP_2:.*]] = arith.constant 1 : i32
170! CHECK:   %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %[[J_STEP_2]] overflow<nsw> : i32
171! CHECK:   fir.store %[[LOOP_VAR_J_NEXT]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
172! CHECK:   cf.br ^[[HEADER_J]]
173! CHECK: ^[[EXIT_J]]:
174! CHECK:   %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
175! CHECK:   %[[ONE_1:.*]] = arith.constant 1 : i32
176! CHECK:   %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[ONE_1]] : i32
177! CHECK:   fir.store %[[TRIP_VAR_I_NEXT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
178! CHECK:   %[[LOOP_VAR_I:.*]] = fir.load %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
179! CHECK:   %[[I_STEP_2:.*]] = arith.constant 1 : i32
180! CHECK:   %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP_2]] overflow<nsw> : i32
181! CHECK:   fir.store %[[LOOP_VAR_I_NEXT]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
182! CHECK:   cf.br ^[[HEADER_I]]
183! CHECK: ^[[EXIT_I]]:
184! CHECK:   return
185
186! Test the existence of a structured loop inside an unstructured loop.
187! Only minimal checks are inserted for the structured loop.
188subroutine nested_structured_in_unstructured()
189  integer :: i, j
190  do i=1,100
191    do j=1,100
192    end do
193    goto 404
194    404 continue
195  end do
196end subroutine
197! CHECK-LABEL: nested_structured_in_unstructured
198! CHECK:   %[[TRIP_VAR_I_REF:.*]] = fir.alloca i32
199! CHECK:   %[[LOOP_VAR_I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_structured_in_unstructuredEi"}
200! CHECK:   %[[LOOP_VAR_J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_structured_in_unstructuredEj"}
201! CHECK:   %[[I_START:.*]] = arith.constant 1 : i32
202! CHECK:   %[[I_END:.*]] = arith.constant 100 : i32
203! CHECK:   %[[I_STEP:.*]] = arith.constant 1 : i32
204! CHECK:   %[[TMP1:.*]] = arith.subi %[[I_END]], %[[I_START]] : i32
205! CHECK:   %[[TMP2:.*]] = arith.addi %[[TMP1]], %[[I_STEP]] : i32
206! CHECK:   %[[TRIP_COUNT:.*]] = arith.divsi %[[TMP2]], %[[I_STEP]] : i32
207! CHECK:   fir.store %[[TRIP_COUNT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
208! CHECK:   fir.store %[[I_START]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
209! CHECK:   cf.br ^[[HEADER:.*]]
210! CHECK: ^[[HEADER]]:
211! CHECK:   %[[TRIP_VAR:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
212! CHECK:   %[[ZERO:.*]] = arith.constant 0 : i32
213! CHECK:   %[[COND:.*]] = arith.cmpi sgt, %[[TRIP_VAR]], %[[ZERO]] : i32
214! CHECK:   cf.cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
215! CHECK: ^[[BODY]]:
216! CHECK:   %{{.*}} = fir.do_loop %[[J_INDEX:[^ ]*]] =
217! CHECK-SAME: %{{.*}} to %{{.*}} step %[[ST:[^ ]*]]
218! CHECK-SAME: iter_args(%[[J_IV:.*]] = %{{.*}}) -> (index, i32) {
219! CHECK:     fir.store %[[J_IV]] to %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
220! CHECK:     %[[J_INDEX_NEXT:.*]] = arith.addi %[[J_INDEX]], %[[ST]] overflow<nsw> : index
221! CHECK:     %[[LOOP_VAR_J:.*]] = fir.load %[[LOOP_VAR_J_REF]] : !fir.ref<i32>
222! CHECK:     %[[LOOP_VAR_J_NEXT:.*]] = arith.addi %[[LOOP_VAR_J]], %{{[^ ]*}} overflow<nsw> : i32
223! CHECK:   }
224! CHECK:   %[[TRIP_VAR_I:.*]] = fir.load %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
225! CHECK:   %[[C1_3:.*]] = arith.constant 1 : i32
226! CHECK:   %[[TRIP_VAR_I_NEXT:.*]] = arith.subi %[[TRIP_VAR_I]], %[[C1_3]] : i32
227! CHECK:   fir.store %[[TRIP_VAR_I_NEXT]] to %[[TRIP_VAR_I_REF]] : !fir.ref<i32>
228! CHECK:   %[[LOOP_VAR_I:.*]] = fir.load %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
229! CHECK:   %[[I_STEP_2:.*]] = arith.constant 1 : i32
230! CHECK:   %[[LOOP_VAR_I_NEXT:.*]] = arith.addi %[[LOOP_VAR_I]], %[[I_STEP_2]] overflow<nsw> : i32
231! CHECK:   fir.store %[[LOOP_VAR_I_NEXT]] to %[[LOOP_VAR_I_REF]] : !fir.ref<i32>
232! CHECK:   cf.br ^[[HEADER]]
233! CHECK: ^[[EXIT]]:
234! CHECK:   return
235