xref: /llvm-project/flang/test/Transforms/stack-arrays.fir (revision 12ba74e181bd6641b532e271f3bfabf53066b1c0)
1cc14bf22STom Eccles// RUN: fir-opt --stack-arrays %s | FileCheck %s
2cc14bf22STom Eccles
3cc14bf22STom Eccles// Simplest transformation
4cc14bf22STom Ecclesfunc.func @simple() {
5cc14bf22STom Eccles  %0 = fir.allocmem !fir.array<42xi32>
6cc14bf22STom Eccles  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
7cc14bf22STom Eccles  return
8cc14bf22STom Eccles}
9cc14bf22STom Eccles// CHECK: func.func @simple() {
10cc14bf22STom Eccles// CHECK-NEXT: fir.alloca !fir.array<42xi32>
11cc14bf22STom Eccles// CHECK-NEXT: return
12cc14bf22STom Eccles// CHECK-NEXT: }
13cc14bf22STom Eccles
14cc14bf22STom Eccles// Check fir.must_be_heap allocations are not moved
15cc14bf22STom Ecclesfunc.func @must_be_heap() {
16cc14bf22STom Eccles  %0 = fir.allocmem !fir.array<42xi32> {fir.must_be_heap = true}
17cc14bf22STom Eccles  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
18cc14bf22STom Eccles  return
19cc14bf22STom Eccles}
20cc14bf22STom Eccles// CHECK:      func.func @must_be_heap() {
21cc14bf22STom Eccles// CHECK-NEXT:   %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32> {fir.must_be_heap = true}
22cc14bf22STom Eccles// CHECK-NEXT:   fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<42xi32>>
23cc14bf22STom Eccles// CHECK-NEXT:   return
24cc14bf22STom Eccles// CHECK-NEXT: }
25cc14bf22STom Eccles
26cc14bf22STom Eccles// Check the data-flow-analysis can detect cases where we aren't sure if memory
27cc14bf22STom Eccles// is freed by the end of the function
28cc14bf22STom Ecclesfunc.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
29cc14bf22STom Eccles  %7 = arith.constant 42 : index
30cc14bf22STom Eccles  %8 = fir.allocmem !fir.array<?xi32>, %7 {uniq_name = "_QFdfa1Earr.alloc"}
31cc14bf22STom Eccles  %9 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
32cc14bf22STom Eccles  %10 = fir.convert %9 : (!fir.logical<4>) -> i1
33cc14bf22STom Eccles  fir.if %10 {
34cc14bf22STom Eccles    fir.freemem %8 : !fir.heap<!fir.array<?xi32>>
35cc14bf22STom Eccles  } else {
36cc14bf22STom Eccles  }
37cc14bf22STom Eccles  return
38cc14bf22STom Eccles}
39cc14bf22STom Eccles// CHECK:      func.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
40cc14bf22STom Eccles// CHECK-NEXT:   %[[C42:.*]] = arith.constant 42 : index
41cc14bf22STom Eccles// CHECK-NEXT:   %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[C42]] {uniq_name = "_QFdfa1Earr.alloc"}
42cc14bf22STom Eccles// CHECK-NEXT:   %[[LOGICAL:.*]] = fir.load %arg0 : !fir.ref<!fir.logical<4>>
43cc14bf22STom Eccles// CHECK-NEXT:   %[[BOOL:.*]] = fir.convert %[[LOGICAL]] : (!fir.logical<4>) -> i1
44cc14bf22STom Eccles// CHECK-NEXT:   fir.if %[[BOOL]] {
45cc14bf22STom Eccles// CHECK-NEXT:     fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
46cc14bf22STom Eccles// CHECK-NEXT:   } else {
47cc14bf22STom Eccles// CHECK-NEXT:   }
48cc14bf22STom Eccles// CHECK-NEXT:   return
49cc14bf22STom Eccles// CHECK-NEXT: }
50cc14bf22STom Eccles
511b0ec398SSacha Ballantyne// Check scf.if
52cc14bf22STom Ecclesfunc.func @dfa2(%arg0: i1) {
53cc14bf22STom Eccles  %a = fir.allocmem !fir.array<1xi8>
54cc14bf22STom Eccles  scf.if %arg0 {
55cc14bf22STom Eccles    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
56cc14bf22STom Eccles  } else {
57cc14bf22STom Eccles  }
58cc14bf22STom Eccles  return
59cc14bf22STom Eccles}
60cc14bf22STom Eccles// CHECK:     func.func @dfa2(%arg0: i1) {
61cc14bf22STom Eccles// CHECK-NEXT:  %[[MEM:.*]] = fir.allocmem !fir.array<1xi8>
62cc14bf22STom Eccles// CHECK-NEXT:  scf.if %arg0 {
63cc14bf22STom Eccles// CHECK-NEXT:    fir.freemem %[[MEM]] : !fir.heap<!fir.array<1xi8>>
64cc14bf22STom Eccles// CHECK-NEXT:  } else {
65cc14bf22STom Eccles// CHECK-NEXT:  }
66cc14bf22STom Eccles// CHECK-NEXT:  return
67cc14bf22STom Eccles// CHECK-NEXT:  }
68cc14bf22STom Eccles
691b0ec398SSacha Ballantyne// Check freemem in both regions
701b0ec398SSacha Ballantynefunc.func @dfa3(%arg0: i1) {
711b0ec398SSacha Ballantyne  %a = fir.allocmem !fir.array<1xi8>
721b0ec398SSacha Ballantyne  fir.if %arg0 {
731b0ec398SSacha Ballantyne    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
741b0ec398SSacha Ballantyne  } else {
751b0ec398SSacha Ballantyne    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
761b0ec398SSacha Ballantyne  }
771b0ec398SSacha Ballantyne  return
781b0ec398SSacha Ballantyne}
791b0ec398SSacha Ballantyne// CHECK:     func.func @dfa3(%arg0: i1) {
801b0ec398SSacha Ballantyne// CHECK-NEXT:  %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
811b0ec398SSacha Ballantyne// CHECK-NEXT:  fir.if %arg0 {
821b0ec398SSacha Ballantyne// CHECK-NEXT:  } else {
831b0ec398SSacha Ballantyne// CHECK-NEXT:  }
841b0ec398SSacha Ballantyne// CHECK-NEXT:  return
851b0ec398SSacha Ballantyne// CHECK-NEXT:  }
861b0ec398SSacha Ballantyne
87408f4196STom Ecclesfunc.func private @dfa3a_foo(!fir.ref<!fir.array<1xi8>>) -> ()
88408f4196STom Ecclesfunc.func private @dfa3a_bar(!fir.ref<!fir.array<1xi8>>) -> ()
89408f4196STom Eccles
90408f4196STom Eccles// Check freemem in both regions, with other uses
91408f4196STom Ecclesfunc.func @dfa3a(%arg0: i1) {
92408f4196STom Eccles  %a = fir.allocmem !fir.array<1xi8>
93408f4196STom Eccles  fir.if %arg0 {
94408f4196STom Eccles    %ref = fir.convert %a : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
95408f4196STom Eccles    func.call @dfa3a_foo(%ref) : (!fir.ref<!fir.array<1xi8>>) -> ()
96408f4196STom Eccles    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
97408f4196STom Eccles  } else {
98408f4196STom Eccles    %ref = fir.convert %a : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
99408f4196STom Eccles    func.call @dfa3a_bar(%ref) : (!fir.ref<!fir.array<1xi8>>) -> ()
100408f4196STom Eccles    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
101408f4196STom Eccles  }
102408f4196STom Eccles  return
103408f4196STom Eccles}
104408f4196STom Eccles// CHECK:     func.func @dfa3a(%arg0: i1) {
105408f4196STom Eccles// CHECK-NEXT:  %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
106775de675STom Eccles// CHECK-NEXT:  %[[HEAP:.*]] = fir.convert %[[MEM]] : (!fir.ref<!fir.array<1xi8>>) -> !fir.heap<!fir.array<1xi8>>
107408f4196STom Eccles// CHECK-NEXT:  fir.if %arg0 {
108775de675STom Eccles// CHECK-NEXT:    %[[REF:.*]] = fir.convert %[[HEAP]] : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
109775de675STom Eccles// CHECK-NEXT:    func.call @dfa3a_foo(%[[REF]])
110408f4196STom Eccles// CHECK-NEXT:  } else {
111775de675STom Eccles// CHECK-NEXT:    %[[REF:.*]] = fir.convert %[[HEAP]] : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
112775de675STom Eccles// CHECK-NEXT:    func.call @dfa3a_bar(%[[REF]])
113408f4196STom Eccles// CHECK-NEXT:  }
114408f4196STom Eccles// CHECK-NEXT:  return
115408f4196STom Eccles// CHECK-NEXT:  }
116408f4196STom Eccles
117cc14bf22STom Eccles// check the alloca is placed after all operands become available
118cc14bf22STom Ecclesfunc.func @placement1() {
119cc14bf22STom Eccles  // do some stuff with other ssa values
120cc14bf22STom Eccles  %1 = arith.constant 1 : index
121cc14bf22STom Eccles  %2 = arith.constant 2 : index
122cc14bf22STom Eccles  %3 = arith.addi %1, %2 : index
123cc14bf22STom Eccles  // operand is now available
124cc14bf22STom Eccles  %4 = fir.allocmem !fir.array<?xi32>, %3
125cc14bf22STom Eccles  // ...
126cc14bf22STom Eccles  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
127cc14bf22STom Eccles  return
128cc14bf22STom Eccles}
129cc14bf22STom Eccles// CHECK:      func.func @placement1() {
130ddc98929Smlevesquedion// CHECK-NEXT:   %[[ARG:.*]] = arith.constant 3 : index
131cc14bf22STom Eccles// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[ARG]]
132cc14bf22STom Eccles// CHECK-NEXT:   return
133cc14bf22STom Eccles// CHECK-NEXT: }
134cc14bf22STom Eccles
135cc14bf22STom Eccles// check that if there are no operands, then the alloca is placed early
136cc14bf22STom Ecclesfunc.func @placement2() {
137cc14bf22STom Eccles  // do some stuff with other ssa values
138cc14bf22STom Eccles  %1 = arith.constant 1 : index
139cc14bf22STom Eccles  %2 = arith.constant 2 : index
140cc14bf22STom Eccles  %3 = arith.addi %1, %2 : index
141cc14bf22STom Eccles  %4 = fir.allocmem !fir.array<42xi32>
142cc14bf22STom Eccles  // ...
143cc14bf22STom Eccles  fir.freemem %4 : !fir.heap<!fir.array<42xi32>>
144cc14bf22STom Eccles  return
145cc14bf22STom Eccles}
146cc14bf22STom Eccles// CHECK:      func.func @placement2() {
147cc14bf22STom Eccles// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
148cc14bf22STom Eccles// CHECK-NEXT:   %[[ONE:.*]] = arith.constant 1 : index
149cc14bf22STom Eccles// CHECK-NEXT:   %[[TWO:.*]] = arith.constant 2 : index
150cc14bf22STom Eccles// CHECK-NEXT:   %[[SUM:.*]] = arith.addi %[[ONE]], %[[TWO]] : index
151cc14bf22STom Eccles// CHECK-NEXT:   return
152cc14bf22STom Eccles// CHECK-NEXT: }
153cc14bf22STom Eccles
154cc14bf22STom Eccles// check that stack allocations which must be placed in loops use stacksave
155cc14bf22STom Ecclesfunc.func @placement3() {
156cc14bf22STom Eccles  %c1 = arith.constant 1 : index
157cc14bf22STom Eccles  %c1_i32 = fir.convert %c1 : (index) -> i32
158cc14bf22STom Eccles  %c2 = arith.constant 2 : index
159cc14bf22STom Eccles  %c10 = arith.constant 10 : index
160cc14bf22STom Eccles  %0:2 = fir.do_loop %arg0 = %c1 to %c10 step %c1 iter_args(%arg1 = %c1_i32) -> (index, i32) {
161cc14bf22STom Eccles    %3 = arith.addi %c1, %c2 : index
162cc14bf22STom Eccles    // operand is now available
163cc14bf22STom Eccles    %4 = fir.allocmem !fir.array<?xi32>, %3
164cc14bf22STom Eccles    // ...
165cc14bf22STom Eccles    fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
166cc14bf22STom Eccles    fir.result %3, %c1_i32 : index, i32
167cc14bf22STom Eccles  }
168cc14bf22STom Eccles  return
169cc14bf22STom Eccles}
170cc14bf22STom Eccles// CHECK:      func.func @placement3() {
171cc14bf22STom Eccles// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
172cc14bf22STom Eccles// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
173cc14bf22STom Eccles// CHECK-NEXT:   %[[C2:.*]] = arith.constant 2 : index
174cc14bf22STom Eccles// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
175cc14bf22STom Eccles// CHECK-NEXT:   fir.do_loop
176cc14bf22STom Eccles// CHECK-NEXT:     %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
1775aaf384bSTom Eccles// CHECK-NEXT:     %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
178cc14bf22STom Eccles// CHECK-NEXT:     %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[SUM]]
1795aaf384bSTom Eccles// CHECK-NEXT:     llvm.intr.stackrestore %[[SP]] : !llvm.ptr
180cc14bf22STom Eccles// CHECK-NEXT:     fir.result
181cc14bf22STom Eccles// CHECK-NEXT:   }
182cc14bf22STom Eccles// CHECK-NEXT:   return
183cc14bf22STom Eccles// CHECK-NEXT: }
184cc14bf22STom Eccles
185cc14bf22STom Eccles// check that stack save/restore are used in CFG loops
186cc14bf22STom Ecclesfunc.func @placement4(%arg0 : i1) {
187cc14bf22STom Eccles  %c1 = arith.constant 1 : index
188cc14bf22STom Eccles  %c1_i32 = fir.convert %c1 : (index) -> i32
189cc14bf22STom Eccles  %c2 = arith.constant 2 : index
190cc14bf22STom Eccles  %c10 = arith.constant 10 : index
191cc14bf22STom Eccles  cf.br ^bb1
192cc14bf22STom Eccles^bb1:
193cc14bf22STom Eccles  %3 = arith.addi %c1, %c2 : index
194cc14bf22STom Eccles  // operand is now available
195cc14bf22STom Eccles  %4 = fir.allocmem !fir.array<?xi32>, %3
196cc14bf22STom Eccles  // ...
197cc14bf22STom Eccles  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
198cc14bf22STom Eccles  cf.cond_br %arg0, ^bb1, ^bb2
199cc14bf22STom Eccles^bb2:
200cc14bf22STom Eccles  return
201cc14bf22STom Eccles}
202cc14bf22STom Eccles// CHECK:      func.func @placement4(%arg0: i1) {
203cc14bf22STom Eccles// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
204cc14bf22STom Eccles// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
205cc14bf22STom Eccles// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
206cc14bf22STom Eccles// CHECK-NEXT:   cf.br ^bb1
207cc14bf22STom Eccles// CHECK-NEXT: ^bb1:
208ddc98929Smlevesquedion// CHECK-NEXT:   %[[C3:.*]] = arith.constant 3 : index
2095aaf384bSTom Eccles// CHECK-NEXT:   %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
210ddc98929Smlevesquedion// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[C3]]
2115aaf384bSTom Eccles// CHECK-NEXT:   llvm.intr.stackrestore %[[SP]] : !llvm.ptr
212cc14bf22STom Eccles// CHECK-NEXT:   cf.cond_br %arg0, ^bb1, ^bb2
213cc14bf22STom Eccles// CHECK-NEXT: ^bb2:
214cc14bf22STom Eccles// CHECK-NEXT:   return
215cc14bf22STom Eccles// CHECK-NEXT: }
216cc14bf22STom Eccles
217cc14bf22STom Eccles// check that stacksave is not used when there is an intervening alloca
218cc14bf22STom Ecclesfunc.func @placement5() {
219cc14bf22STom Eccles  %c1 = arith.constant 1 : index
220cc14bf22STom Eccles  %c1_i32 = fir.convert %c1 : (index) -> i32
221cc14bf22STom Eccles  %c2 = arith.constant 2 : index
222cc14bf22STom Eccles  %c10 = arith.constant 10 : index
223cc14bf22STom Eccles  %0:2 = fir.do_loop %arg0 = %c1 to %c10 step %c1 iter_args(%arg1 = %c1_i32) -> (index, i32) {
224cc14bf22STom Eccles    %3 = arith.addi %c1, %c2 : index
225cc14bf22STom Eccles    // operand is now available
226cc14bf22STom Eccles    %4 = fir.allocmem !fir.array<?xi32>, %3
227cc14bf22STom Eccles    %5 = fir.alloca i32
228cc14bf22STom Eccles    fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
229cc14bf22STom Eccles    fir.result %3, %c1_i32 : index, i32
230cc14bf22STom Eccles  }
231cc14bf22STom Eccles  return
232cc14bf22STom Eccles}
233cc14bf22STom Eccles// CHECK:      func.func @placement5() {
234cc14bf22STom Eccles// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
235cc14bf22STom Eccles// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
236cc14bf22STom Eccles// CHECK-NEXT:   %[[C2:.*]] = arith.constant 2 : index
237cc14bf22STom Eccles// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
238cc14bf22STom Eccles// CHECK-NEXT:   fir.do_loop
239cc14bf22STom Eccles// CHECK-NEXT:     %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
240cc14bf22STom Eccles// CHECK-NEXT:     %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[SUM]]
241cc14bf22STom Eccles// CHECK-NEXT:     %[[IDX:.*]] = fir.alloca i32
242cc14bf22STom Eccles// CHECK-NEXT:     fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
243cc14bf22STom Eccles// CHECK-NEXT:     fir.result
244cc14bf22STom Eccles// CHECK-NEXT:   }
245cc14bf22STom Eccles// CHECK-NEXT:   return
246cc14bf22STom Eccles// CHECK-NEXT: }
247cc14bf22STom Eccles
248cc14bf22STom Eccles// check that stack save/restore are not used when the memalloc and freemem are
249cc14bf22STom Eccles// in different blocks
250cc14bf22STom Ecclesfunc.func @placement6(%arg0: i1) {
251cc14bf22STom Eccles  %c1 = arith.constant 1 : index
252cc14bf22STom Eccles  %c1_i32 = fir.convert %c1 : (index) -> i32
253cc14bf22STom Eccles  %c2 = arith.constant 2 : index
254cc14bf22STom Eccles  %c10 = arith.constant 10 : index
255cc14bf22STom Eccles  cf.br ^bb1
256cc14bf22STom Eccles^bb1:
257cc14bf22STom Eccles  %3 = arith.addi %c1, %c2 : index
258cc14bf22STom Eccles  // operand is now available
259cc14bf22STom Eccles  %4 = fir.allocmem !fir.array<?xi32>, %3
260cc14bf22STom Eccles  // ...
261cc14bf22STom Eccles  cf.cond_br %arg0, ^bb2, ^bb3
262cc14bf22STom Eccles^bb2:
263cc14bf22STom Eccles  // ...
264cc14bf22STom Eccles  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
265cc14bf22STom Eccles  cf.br ^bb1
266cc14bf22STom Eccles^bb3:
267cc14bf22STom Eccles  // ...
268cc14bf22STom Eccles  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
269cc14bf22STom Eccles  cf.br ^bb1
270cc14bf22STom Eccles}
271cc14bf22STom Eccles// CHECK:      func.func @placement6(%arg0: i1) {
272cc14bf22STom Eccles// CHECK-NEXT:   %[[c1:.*]] = arith.constant 1 : index
273cc14bf22STom Eccles// CHECK-NEXT:   %[[c1_i32:.*]] = fir.convert %[[c1]] : (index) -> i32
274cc14bf22STom Eccles// CHECK-NEXT:   %[[c2:.*]] = arith.constant 2 : index
275cc14bf22STom Eccles// CHECK-NEXT:   %[[c10:.*]] = arith.constant 10 : index
276cc14bf22STom Eccles// CHECK-NEXT:   cf.br ^bb1
277cc14bf22STom Eccles// CHECK-NEXT: ^bb1:
278cc14bf22STom Eccles// CHECK-NEXT:   %[[ADD:.*]] = arith.addi %[[c1]], %[[c2]] : index
279cc14bf22STom Eccles// CHECK-NEXT:   %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[ADD]]
280cc14bf22STom Eccles// CHECK-NEXT:   cf.cond_br %arg0, ^bb2, ^bb3
281cc14bf22STom Eccles// CHECK-NEXT: ^bb2:
282cc14bf22STom Eccles// CHECK-NEXT:   fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
283cc14bf22STom Eccles// CHECK-NEXT:   cf.br ^bb1
284cc14bf22STom Eccles// CHECK-NEXT: ^bb3:
285cc14bf22STom Eccles// CHECK-NEXT:   fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
286cc14bf22STom Eccles// CHECK-NEXT:   cf.br ^bb1
287cc14bf22STom Eccles// CHECK-NEXT: }
288cc14bf22STom Eccles
289cc14bf22STom Eccles// Check multiple returns, where the memory is always freed
290cc14bf22STom Ecclesfunc.func @returns(%arg0: i1) {
291cc14bf22STom Eccles  %0 = fir.allocmem !fir.array<42xi32>
292cc14bf22STom Eccles  cf.cond_br %arg0, ^bb1, ^bb2
293cc14bf22STom Eccles^bb1:
294cc14bf22STom Eccles  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
295cc14bf22STom Eccles  return
296cc14bf22STom Eccles^bb2:
297cc14bf22STom Eccles  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
298cc14bf22STom Eccles  return
299cc14bf22STom Eccles}
300cc14bf22STom Eccles// CHECK:      func.func @returns(%[[COND:.*]]: i1) {
301cc14bf22STom Eccles// CHECK-NEXT:   %[[ALLOC:.*]] = fir.alloca !fir.array<42xi32>
302cc14bf22STom Eccles// CHECK-NEXT:   cf.cond_br %[[COND]], ^bb1, ^bb2
303cc14bf22STom Eccles// CHECK-NEXT: ^bb1:
304cc14bf22STom Eccles// CHECK-NEXT:   return
305cc14bf22STom Eccles// CHECK-NEXT: ^bb2:
306cc14bf22STom Eccles// CHECK-NEXT:   return
307cc14bf22STom Eccles// CHECK-NEXT: }
308cc14bf22STom Eccles
309cc14bf22STom Eccles// Check multiple returns, where the memory is not freed on one branch
310cc14bf22STom Ecclesfunc.func @returns2(%arg0: i1) {
311cc14bf22STom Eccles  %0 = fir.allocmem !fir.array<42xi32>
312cc14bf22STom Eccles  cf.cond_br %arg0, ^bb1, ^bb2
313cc14bf22STom Eccles^bb1:
314cc14bf22STom Eccles  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
315cc14bf22STom Eccles  return
316cc14bf22STom Eccles^bb2:
317cc14bf22STom Eccles  return
318cc14bf22STom Eccles}
319cc14bf22STom Eccles// CHECK:      func.func @returns2(%[[COND:.*]]: i1) {
320cc14bf22STom Eccles// CHECK-NEXT:   %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32>
321cc14bf22STom Eccles// CHECK-NEXT:   cf.cond_br %[[COND]], ^bb1, ^bb2
322cc14bf22STom Eccles// CHECK-NEXT: ^bb1:
323cc14bf22STom Eccles// CHECK-NEXT:   fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<42xi32>>
324cc14bf22STom Eccles// CHECK-NEXT:   return
325cc14bf22STom Eccles// CHECK-NEXT: ^bb2:
326cc14bf22STom Eccles// CHECK-NEXT:   return
327cc14bf22STom Eccles// CHECK-NEXT: }
328cc14bf22STom Eccles
329cc14bf22STom Eccles// Check allocations are not moved outside of an omp region
330cc14bf22STom Ecclesfunc.func @omp_placement1() {
331cc14bf22STom Eccles  omp.sections {
332cc14bf22STom Eccles    omp.section {
333cc14bf22STom Eccles      %mem = fir.allocmem !fir.array<42xi32>
334cc14bf22STom Eccles      fir.freemem %mem : !fir.heap<!fir.array<42xi32>>
335cc14bf22STom Eccles      omp.terminator
336cc14bf22STom Eccles    }
337cc14bf22STom Eccles    omp.terminator
338cc14bf22STom Eccles  }
339cc14bf22STom Eccles  return
340cc14bf22STom Eccles}
341cc14bf22STom Eccles// CHECK:      func.func @omp_placement1() {
342464d321eSKareem Ergawy// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
343464d321eSKareem Ergawy// CHECK-NEXT:   %[[MEM_CONV:.*]] = fir.convert %[[MEM]] : (!fir.ref<!fir.array<42xi32>>) -> !fir.heap<!fir.array<42xi32>>
344cc14bf22STom Eccles// CHECK-NEXT:   omp.sections {
345cc14bf22STom Eccles// CHECK-NEXT:     omp.section {
346cc14bf22STom Eccles// CHECK-NEXT:       omp.terminator
347cc14bf22STom Eccles// CHECK-NEXT:     }
348cc14bf22STom Eccles// CHECK-NEXT:     omp.terminator
349cc14bf22STom Eccles// CHECK-NEXT:   }
350cc14bf22STom Eccles// CHECK-NEXT:   return
351cc14bf22STom Eccles// CHECK-NEXT: }
3527a49d50fSTom Eccles
3537a49d50fSTom Eccles// function terminated by stop statement
3547a49d50fSTom Ecclesfunc.func @stop_terminator() {
3557a49d50fSTom Eccles  %0 = fir.allocmem !fir.array<42xi32>
3567a49d50fSTom Eccles  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
3577a49d50fSTom Eccles  %c0_i32 = arith.constant 0 : i32
3587a49d50fSTom Eccles  %false = arith.constant false
359*12ba74e1SValentin Clement (バレンタイン クレメン)  fir.call @_FortranAStopStatement(%c0_i32, %false, %false) : (i32, i1, i1) -> ()
3607a49d50fSTom Eccles  fir.unreachable
3617a49d50fSTom Eccles}
3627a49d50fSTom Eccles// CHECK: func.func @stop_terminator() {
3637a49d50fSTom Eccles// CHECK-NEXT: fir.alloca !fir.array<42xi32>
3647a49d50fSTom Eccles// CHECK-NEXT:  %[[ZERO:.*]] = arith.constant 0 : i32
3657a49d50fSTom Eccles// CHECK-NEXT:  %[[FALSE:.*]] = arith.constant false
366*12ba74e1SValentin Clement (バレンタイン クレメン)// CHECK-NEXT:  fir.call @_FortranAStopStatement(%[[ZERO]], %[[FALSE]], %[[FALSE]]) : (i32, i1, i1) -> ()
3677a49d50fSTom Eccles// CHECK-NEXT:  fir.unreachable
3687a49d50fSTom Eccles// CHECK-NEXT: }
369464d321eSKareem Ergawy
370464d321eSKareem Ergawy
371464d321eSKareem Ergawy// check that stack allocations that use fir.declare which must be placed in loops
372464d321eSKareem Ergawy// use stacksave
373464d321eSKareem Ergawyfunc.func @placement_loop_declare() {
374464d321eSKareem Ergawy  %c1 = arith.constant 1 : index
375464d321eSKareem Ergawy  %c1_i32 = fir.convert %c1 : (index) -> i32
376464d321eSKareem Ergawy  %c2 = arith.constant 2 : index
377464d321eSKareem Ergawy  %c10 = arith.constant 10 : index
378464d321eSKareem Ergawy  %0:2 = fir.do_loop %arg0 = %c1 to %c10 step %c1 iter_args(%arg1 = %c1_i32) -> (index, i32) {
379464d321eSKareem Ergawy    %3 = arith.addi %c1, %c2 : index
380464d321eSKareem Ergawy    // operand is now available
381464d321eSKareem Ergawy    %4 = fir.allocmem !fir.array<?xi32>, %3
382303249c4STom Eccles    %shape = fir.shape %3 : (index) -> !fir.shape<1>
383303249c4STom Eccles    %5 = fir.declare %4(%shape) {uniq_name = "temp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.heap<!fir.array<?xi32>>
384464d321eSKareem Ergawy    // ...
385464d321eSKareem Ergawy    fir.freemem %5 : !fir.heap<!fir.array<?xi32>>
386464d321eSKareem Ergawy    fir.result %3, %c1_i32 : index, i32
387464d321eSKareem Ergawy  }
388464d321eSKareem Ergawy  return
389464d321eSKareem Ergawy}
390464d321eSKareem Ergawy// CHECK:      func.func @placement_loop_declare() {
391464d321eSKareem Ergawy// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
392464d321eSKareem Ergawy// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
393464d321eSKareem Ergawy// CHECK-NEXT:   %[[C2:.*]] = arith.constant 2 : index
394464d321eSKareem Ergawy// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
395464d321eSKareem Ergawy// CHECK-NEXT:   fir.do_loop
396464d321eSKareem Ergawy// CHECK-NEXT:     %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
3975aaf384bSTom Eccles// CHECK-NEXT:     %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
398464d321eSKareem Ergawy// CHECK-NEXT:     %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[SUM]]
3995aaf384bSTom Eccles// CHECK:          llvm.intr.stackrestore %[[SP]] : !llvm.ptr
400464d321eSKareem Ergawy// CHECK-NEXT:     fir.result
401464d321eSKareem Ergawy// CHECK-NEXT:   }
402464d321eSKareem Ergawy// CHECK-NEXT:   return
403464d321eSKareem Ergawy// CHECK-NEXT: }
404303249c4STom Eccles
405303249c4STom Eccles// Can we look through fir.convert and fir.declare?
406303249c4STom Ecclesfunc.func @lookthrough() {
407303249c4STom Eccles  %0 = fir.allocmem !fir.array<42xi32>
408303249c4STom Eccles  %c42 = arith.constant 42 : index
409303249c4STom Eccles  %shape = fir.shape %c42 : (index) -> !fir.shape<1>
410303249c4STom Eccles  %1 = fir.declare %0(%shape) {uniq_name = "name"} : (!fir.heap<!fir.array<42xi32>>, !fir.shape<1>) -> !fir.heap<!fir.array<42xi32>>
411303249c4STom Eccles  %2 = fir.convert %1 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
412303249c4STom Eccles  // use the ref so the converts aren't folded
413303249c4STom Eccles  %3 = fir.load %2 : !fir.ref<!fir.array<42xi32>>
414303249c4STom Eccles  %4 = fir.convert %2 : (!fir.ref<!fir.array<42xi32>>) -> !fir.heap<!fir.array<42xi32>>
415303249c4STom Eccles  fir.freemem %4 : !fir.heap<!fir.array<42xi32>>
416303249c4STom Eccles  return
417303249c4STom Eccles}
418303249c4STom Eccles// CHECK: func.func @lookthrough() {
419303249c4STom Eccles// CHECK:     fir.alloca !fir.array<42xi32>
420303249c4STom Eccles// CHECK-NOT: fir.freemem
421e3cd88a7SSlava Zakharin
422e3cd88a7SSlava Zakharin// StackArrays is better to find fir.freemem ops corresponding to fir.allocmem
423e3cd88a7SSlava Zakharin// using the same look through mechanism as during the allocation analysis,
424e3cd88a7SSlava Zakharin// looking through fir.convert and fir.declare.
425e3cd88a7SSlava Zakharinfunc.func @finding_freemem_in_block() {
426e3cd88a7SSlava Zakharin  %c0 = arith.constant 0 : index
427e3cd88a7SSlava Zakharin  %c10_i32 = arith.constant 10 : i32
428e3cd88a7SSlava Zakharin  %c1_i32 = arith.constant 1 : i32
429e3cd88a7SSlava Zakharin  %0 = fir.alloca i32 {bindc_name = "k", uniq_name = "k"}
430e3cd88a7SSlava Zakharin  %1 = fir.declare %0 {uniq_name = "k"} : (!fir.ref<i32>) -> !fir.ref<i32>
431e3cd88a7SSlava Zakharin  fir.store %c1_i32 to %1 : !fir.ref<i32>
432e3cd88a7SSlava Zakharin  cf.br ^bb1
433e3cd88a7SSlava Zakharin^bb1:  // 2 preds: ^bb0, ^bb2
434e3cd88a7SSlava Zakharin  %2 = fir.load %1 : !fir.ref<i32>
435e3cd88a7SSlava Zakharin  %3 = arith.cmpi sle, %2, %c10_i32 : i32
436e3cd88a7SSlava Zakharin  cf.cond_br %3, ^bb2, ^bb3
437e3cd88a7SSlava Zakharin^bb2:  // pred: ^bb1
438e3cd88a7SSlava Zakharin  %4 = fir.declare %1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
439e3cd88a7SSlava Zakharin  %5 = fir.load %4 : !fir.ref<i32>
440e3cd88a7SSlava Zakharin  %6 = fir.convert %5 : (i32) -> index
441e3cd88a7SSlava Zakharin  %7 = arith.cmpi sgt, %6, %c0 : index
442e3cd88a7SSlava Zakharin  %8 = arith.select %7, %6, %c0 : index
443e3cd88a7SSlava Zakharin  %9 = fir.shape %8 : (index) -> !fir.shape<1>
444e3cd88a7SSlava Zakharin  %10 = fir.allocmem !fir.array<?xi32>, %8 {bindc_name = ".tmp.expr_result", uniq_name = ""}
445e3cd88a7SSlava Zakharin  %11 = fir.convert %10 : (!fir.heap<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
446e3cd88a7SSlava Zakharin  %12 = fir.declare %11(%9) {uniq_name = ".tmp.expr_result"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<?xi32>>
447e3cd88a7SSlava Zakharin  %13 = fir.embox %12(%9) : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
448e3cd88a7SSlava Zakharin  %14 = fir.call @_QPfunc(%1) fastmath<fast> : (!fir.ref<i32>) -> !fir.array<?xi32>
449e3cd88a7SSlava Zakharin  fir.save_result %14 to %12(%9) : !fir.array<?xi32>, !fir.ref<!fir.array<?xi32>>, !fir.shape<1>
450e3cd88a7SSlava Zakharin  fir.call @_QPsub(%13) fastmath<fast> : (!fir.box<!fir.array<?xi32>>) -> ()
451e3cd88a7SSlava Zakharin  %15 = fir.convert %12 : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
452e3cd88a7SSlava Zakharin  fir.freemem %15 : !fir.heap<!fir.array<?xi32>>
453e3cd88a7SSlava Zakharin  %16 = fir.load %1 : !fir.ref<i32>
454e3cd88a7SSlava Zakharin  %17 = arith.addi %16, %c1_i32 : i32
455e3cd88a7SSlava Zakharin  fir.store %17 to %1 : !fir.ref<i32>
456e3cd88a7SSlava Zakharin  cf.br ^bb1
457e3cd88a7SSlava Zakharin^bb3:  // pred: ^bb1
458e3cd88a7SSlava Zakharin  return
459e3cd88a7SSlava Zakharin}
460e3cd88a7SSlava Zakharin// CHECK: func.func @finding_freemem_in_block() {
461e3cd88a7SSlava Zakharin// CHECK:     fir.alloca !fir.array<?xi32>
462e3cd88a7SSlava Zakharin// CHECK-NOT: fir.freemem
463