1! RUN: bbc -emit-fir -o - %s | FileCheck %s
2! RUN: %flang_fc1 -emit-fir -o - %s | FileCheck %s
3
4! Simple tests for structured ordered loops with loop-control.
5! Tests the structure of the loop, storage to index variable and return and
6! storage of the final value of the index variable.
7
8! Test a simple loop with the final value of the index variable read outside the loop
9! CHECK-LABEL: simple_loop
10subroutine simple_loop
11  ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsimple_loopEi"}
12  integer :: i
13
14  ! CHECK: %[[C1:.*]] = arith.constant 1 : i32
15  ! CHECK: %[[C1_CVT:.*]] = fir.convert %c1_i32 : (i32) -> index
16  ! CHECK: %[[C5:.*]] = arith.constant 5 : i32
17  ! CHECK: %[[C5_CVT:.*]] = fir.convert %c5_i32 : (i32) -> index
18  ! CHECK: %[[C1:.*]] = arith.constant 1 : index
19  ! CHECK: %[[LI_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[C1_CVT]] to %[[C5_CVT]] step %[[C1]] -> index {
20  do i=1,5
21  ! CHECK:   %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
22  ! CHECK:   fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
23  ! CHECK:   %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[C1]] : index
24  ! CHECK:  fir.result %[[LI_NEXT]] : index
25  ! CHECK: }
26  end do
27  ! CHECK: %[[LI_RES_CVT:.*]] = fir.convert %[[LI_RES]] : (index) -> i32
28  ! CHECK: fir.store %[[LI_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
29  ! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
30  ! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[I]]) : (!fir.ref<i8>, i32) -> i1
31  print *, i
32end subroutine
33
34! Test a 2-nested loop with a body composed of a reduction. Values are read from a 2d array.
35! CHECK-LABEL: nested_loop
36subroutine nested_loop
37  ! CHECK: %[[ARR_REF:.*]] = fir.alloca !fir.array<5x5xi32> {bindc_name = "arr", uniq_name = "_QFnested_loopEarr"}
38  ! CHECK: %[[ASUM_REF:.*]] = fir.alloca i32 {bindc_name = "asum", uniq_name = "_QFnested_loopEasum"}
39  ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFnested_loopEi"}
40  ! CHECK: %[[J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFnested_loopEj"}
41  integer :: asum, arr(5,5)
42  integer :: i, j
43  asum = 0
44  ! CHECK: %[[S_I:.*]] = arith.constant 1 : i32
45  ! CHECK: %[[S_I_CVT:.*]] = fir.convert %[[S_I]] : (i32) -> index
46  ! CHECK: %[[E_I:.*]] = arith.constant 5 : i32
47  ! CHECK: %[[E_I_CVT:.*]] = fir.convert %[[E_I]] : (i32) -> index
48  ! CHECK: %[[ST_I:.*]] = arith.constant 1 : index
49  ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_I_CVT]] to %[[E_I_CVT]] step %[[ST_I]] -> index {
50  do i=1,5
51    ! CHECK: %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
52    ! CHECK: fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
53    ! CHECK: %[[S_J:.*]] = arith.constant 1 : i32
54    ! CHECK: %[[S_J_CVT:.*]] = fir.convert %[[S_J]] : (i32) -> index
55    ! CHECK: %[[E_J:.*]] = arith.constant 5 : i32
56    ! CHECK: %[[E_J_CVT:.*]] = fir.convert %[[E_J]] : (i32) -> index
57    ! CHECK: %[[ST_J:.*]] = arith.constant 1 : index
58    ! CHECK: %[[J_RES:.*]] = fir.do_loop %[[LJ:.*]] = %[[S_J_CVT]] to %[[E_J_CVT]] step %[[ST_J]] -> index {
59    do j=1,5
60      ! CHECK: %[[LJ_CVT:.*]] = fir.convert %[[LJ]] : (index) -> i32
61      ! CHECK: fir.store %[[LJ_CVT]] to %[[J_REF]] : !fir.ref<i32>
62      ! CHECK: %[[ASUM:.*]] = fir.load %[[ASUM_REF]] : !fir.ref<i32>
63      ! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
64      ! CHECK: %[[I_CVT:.*]] = fir.convert %[[I]] : (i32) -> i64
65      ! CHECK: %[[C1_I:.*]] = arith.constant 1 : i64
66      ! CHECK: %[[I_INDX:.*]] = arith.subi %[[I_CVT]], %[[C1_I]] : i64
67      ! CHECK: %[[J:.*]] = fir.load %[[J_REF]] : !fir.ref<i32>
68      ! CHECK: %[[J_CVT:.*]] = fir.convert %[[J]] : (i32) -> i64
69      ! CHECK: %[[C1_J:.*]] = arith.constant 1 : i64
70      ! CHECK: %[[J_INDX:.*]] = arith.subi %[[J_CVT]], %[[C1_J]] : i64
71      ! CHECK: %[[ARR_IJ_REF:.*]] = fir.coordinate_of %[[ARR_REF]], %[[I_INDX]], %[[J_INDX]] : (!fir.ref<!fir.array<5x5xi32>>, i64, i64) -> !fir.ref<i32>
72      ! CHECK: %[[ARR_VAL:.*]] = fir.load %[[ARR_IJ_REF]] : !fir.ref<i32>
73      ! CHECK: %[[ASUM_NEW:.*]] = arith.addi %[[ASUM]], %[[ARR_VAL]] : i32
74      ! CHECK: fir.store %[[ASUM_NEW]] to %[[ASUM_REF]] : !fir.ref<i32>
75      asum = asum + arr(i,j)
76      ! CHECK: %[[LJ_NEXT:.*]] = arith.addi %[[LJ]], %[[ST_J]] : index
77      ! CHECK: fir.result %[[LJ_NEXT]] : index
78    ! CHECK: }
79    end do
80    ! CHECK: %[[J_RES_CVT:.*]] = fir.convert %[[J_RES]] : (index) -> i32
81    ! CHECK: fir.store %[[J_RES_CVT]] to %[[J_REF]] : !fir.ref<i32>
82    ! CHECK: %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_I]] : index
83    ! CHECK: fir.result %[[LI_NEXT]] : index
84  ! CHECK: }
85  end do
86  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
87  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
88end subroutine
89
90! Test a downcounting loop
91! CHECK-LABEL: down_counting_loop
92subroutine down_counting_loop()
93  integer :: i
94  ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFdown_counting_loopEi"}
95
96  ! CHECK: %[[C5:.*]] = arith.constant 5 : i32
97  ! CHECK: %[[C5_CVT:.*]] = fir.convert %[[C5]] : (i32) -> index
98  ! CHECK: %[[C1:.*]] = arith.constant 1 : i32
99  ! CHECK: %[[C1_CVT:.*]] = fir.convert %[[C1]] : (i32) -> index
100  ! CHECK: %[[CMINUS1:.*]] = arith.constant -1 : i32
101  ! CHECK: %[[CMINUS1_STEP_CVT:.*]] = fir.convert %[[CMINUS1]] : (i32) -> index
102  ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[C5_CVT]] to %[[C1_CVT]] step %[[CMINUS1_STEP_CVT]] -> index {
103  do i=5,1,-1
104  ! CHECK: %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
105  ! CHECK: fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
106  ! CHECK: %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[CMINUS1_STEP_CVT]] : index
107  ! CHECK: fir.result %[[LI_NEXT]] : index
108  ! CHECK: }
109  end do
110  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
111  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
112end subroutine
113
114! Test a general loop with a variable step
115! CHECK-LABEL: loop_with_variable_step
116! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "st"}) {
117subroutine loop_with_variable_step(s,e,st)
118  integer :: s, e, st
119  ! CHECK: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref<i32>
120  ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index
121  ! CHECK: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref<i32>
122  ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index
123  ! CHECK: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref<i32>
124  ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index
125  ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] -> index {
126  do i=s,e,st
127  ! CHECK:  %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
128  ! CHECK:  fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i32>
129  ! CHECK:  %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_CVT]] : index
130  ! CHECK:  fir.result %[[LI_NEXT]] : index
131  ! CHECK: }
132  end do
133  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
134  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i32>
135end subroutine
136
137! Test usage of pointer variables as index, start, end and step variables
138! CHECK-LABEL: loop_with_pointer_variables
139! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "s", fir.target}, %[[E_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "e", fir.target}, %[[ST_REF:.*]]: !fir.ref<i32> {fir.bindc_name = "st", fir.target}) {
140subroutine loop_with_pointer_variables(s,e,st)
141! CHECK:  %[[E_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEeptr.addr"}
142! CHECK:  %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", fir.target, uniq_name = "_QFloop_with_pointer_variablesEi"}
143! CHECK:  %[[I_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEiptr.addr"}
144! CHECK:  %[[S_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEsptr.addr"}
145! CHECK:  %[[ST_PTR_REF:.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "_QFloop_with_pointer_variablesEstptr.addr"}
146  integer, target :: i
147  integer, target :: s, e, st
148  integer, pointer :: iptr, sptr, eptr, stptr
149
150! CHECK:  %[[I_PTR:.*]] = fir.convert %[[I_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
151! CHECK:  fir.store %[[I_PTR]] to %[[I_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
152! CHECK:  %[[S_PTR:.*]] = fir.convert %[[S_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
153! CHECK:  fir.store %[[S_PTR]] to %[[S_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
154! CHECK:  %[[E_PTR:.*]] = fir.convert %[[E_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
155! CHECK:  fir.store %[[E_PTR]] to %[[E_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
156! CHECK:  %[[ST_PTR:.*]] = fir.convert %[[ST_REF]] : (!fir.ref<i32>) -> !fir.ptr<i32>
157! CHECK:  fir.store %[[ST_PTR]] to %[[ST_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
158  iptr => i
159  sptr => s
160  eptr => e
161  stptr => st
162
163! CHECK:  %[[I_PTR:.*]] = fir.load %[[I_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
164! CHECK:  %[[S_PTR:.*]] = fir.load %[[S_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
165! CHECK:  %[[S:.*]] = fir.load %[[S_PTR]] : !fir.ptr<i32>
166! CHECK:  %[[S_CVT:.*]] = fir.convert %[[S]] : (i32) -> index
167! CHECK:  %[[E_PTR:.*]] = fir.load %[[E_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
168! CHECK:  %[[E:.*]] = fir.load %[[E_PTR]] : !fir.ptr<i32>
169! CHECK:  %[[E_CVT:.*]] = fir.convert %[[E]] : (i32) -> index
170! CHECK:  %[[ST_PTR:.*]] = fir.load %[[ST_PTR_REF]] : !fir.ref<!fir.ptr<i32>>
171! CHECK:  %[[ST:.*]] = fir.load %[[ST_PTR]] : !fir.ptr<i32>
172! CHECK:  %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i32) -> index
173! CHECK:  %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] -> index {
174  do iptr=sptr,eptr,stptr
175! CHECK:    %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i32
176! CHECK:    fir.store %[[LI_CVT]] to %[[I_PTR]] : !fir.ptr<i32>
177! CHECK:    %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_CVT]] : index
178! CHECK:    fir.result %[[LI_NEXT]] : index
179  end do
180! CHECK:  }
181! CHECK:  %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i32
182! CHECK:  fir.store %[[I_RES_CVT:.*]] to %[[I_PTR]] : !fir.ptr<i32>
183end subroutine
184
185! Test usage of non-default integer kind for loop control and loop index variable
186! CHECK-LABEL: loop_with_non_default_integer
187! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<i64> {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref<i64> {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref<i64> {fir.bindc_name = "st"}) {
188subroutine loop_with_non_default_integer(s,e,st)
189  ! CHECK: %[[I_REF:.*]] = fir.alloca i64 {bindc_name = "i", uniq_name = "_QFloop_with_non_default_integerEi"}
190  integer(kind=8):: i
191  ! CHECK: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref<i64>
192  ! CHECK: %[[S_CVT:.*]] = fir.convert %[[S]] : (i64) -> index
193  ! CHECK: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref<i64>
194  ! CHECK: %[[E_CVT:.*]] = fir.convert %[[E]] : (i64) -> index
195  ! CHECK: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref<i64>
196  ! CHECK: %[[ST_CVT:.*]] = fir.convert %[[ST]] : (i64) -> index
197  integer(kind=8) :: s, e, st
198
199  ! CHECK: %[[I_RES:.*]] = fir.do_loop %[[LI:.*]] = %[[S_CVT]] to %[[E_CVT]] step %[[ST_CVT]] -> index {
200  do i=s,e,st
201    ! CHECK: %[[LI_CVT:.*]] = fir.convert %[[LI]] : (index) -> i64
202    ! CHECK: fir.store %[[LI_CVT]] to %[[I_REF]] : !fir.ref<i64>
203    ! CHECK: %[[LI_NEXT:.*]] = arith.addi %[[LI]], %[[ST_CVT]] : index
204    ! CHECK: fir.result %[[LI_NEXT]] : index
205  end do
206  ! CHECK: }
207  ! CHECK: %[[I_RES_CVT:.*]] = fir.convert %[[I_RES]] : (index) -> i64
208  ! CHECK: fir.store %[[I_RES_CVT]] to %[[I_REF]] : !fir.ref<i64>
209end subroutine
210
211! Test real loop control.
212! CHECK-LABEL: loop_with_real_control
213! CHECK-SAME: (%[[S_REF:.*]]: !fir.ref<f32> {fir.bindc_name = "s"}, %[[E_REF:.*]]: !fir.ref<f32> {fir.bindc_name = "e"}, %[[ST_REF:.*]]: !fir.ref<f32> {fir.bindc_name = "st"}) {
214subroutine loop_with_real_control(s,e,st)
215  ! CHECK-DAG: %[[INDEX_REF:.*]] = fir.alloca index
216  ! CHECK-DAG: %[[X_REF:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFloop_with_real_controlEx"}
217  ! CHECK-DAG: %[[S:.*]] = fir.load %[[S_REF]] : !fir.ref<f32>
218  ! CHECK-DAG: %[[E:.*]] = fir.load %[[E_REF]] : !fir.ref<f32>
219  ! CHECK-DAG: %[[ST:.*]] = fir.load %[[ST_REF]] : !fir.ref<f32>
220  real :: x, s, e, st
221
222  ! CHECK: %[[DIFF:.*]] = arith.subf %[[E]], %[[S]] : f32
223  ! CHECK: %[[RANGE:.*]] = arith.addf %[[DIFF]], %[[ST]] : f32
224  ! CHECK: %[[HIGH:.*]] = arith.divf %[[RANGE]], %[[ST]] : f32
225  ! CHECK: %[[HIGH_INDEX:.*]] = fir.convert %[[HIGH]] : (f32) -> index
226  ! CHECK: fir.store %[[HIGH_INDEX]] to %[[INDEX_REF]] : !fir.ref<index>
227  ! CHECK: fir.store %[[S]] to %[[X_REF]] : !fir.ref<f32>
228
229  ! CHECK: br ^[[HDR:.*]]
230  ! CHECK: ^[[HDR]]:  // 2 preds: ^{{.*}}, ^[[EXIT:.*]]
231  ! CHECK-DAG: %[[INDEX:.*]] = fir.load %[[INDEX_REF]] : !fir.ref<index>
232  ! CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index
233  ! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[INDEX]], %[[C0]] : index
234  ! CHECK: cond_br %[[COND]], ^[[BODY:.*]], ^[[EXIT:.*]]
235  do x=s,e,st
236    ! CHECK: ^[[BODY]]:  // pred: ^[[HDR]]
237    ! CHECK-DAG: %[[INDEX2:.*]] = fir.load %[[INDEX_REF]] : !fir.ref<index>
238    ! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
239    ! CHECK: %[[INC:.*]] = arith.subi %[[INDEX2]], %[[C1]] : index
240    ! CHECK: fir.store %[[INC]] to %[[INDEX_REF]] : !fir.ref<index>
241    ! CHECK: %[[X2:.*]] = fir.load %[[X_REF]] : !fir.ref<f32>
242    ! CHECK: %[[XINC:.*]] = arith.addf %[[X2]], %[[ST]] : f32
243    ! CHECK: fir.store %[[XINC]] to %[[X_REF]] : !fir.ref<f32>
244    ! CHECK: br ^[[HDR]]
245  end do
246end subroutine
247