xref: /llvm-project/flang/test/Transforms/stack-arrays.fir (revision 12ba74e181bd6641b532e271f3bfabf53066b1c0)
1// RUN: fir-opt --stack-arrays %s | FileCheck %s
2
3// Simplest transformation
4func.func @simple() {
5  %0 = fir.allocmem !fir.array<42xi32>
6  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
7  return
8}
9// CHECK: func.func @simple() {
10// CHECK-NEXT: fir.alloca !fir.array<42xi32>
11// CHECK-NEXT: return
12// CHECK-NEXT: }
13
14// Check fir.must_be_heap allocations are not moved
15func.func @must_be_heap() {
16  %0 = fir.allocmem !fir.array<42xi32> {fir.must_be_heap = true}
17  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
18  return
19}
20// CHECK:      func.func @must_be_heap() {
21// CHECK-NEXT:   %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32> {fir.must_be_heap = true}
22// CHECK-NEXT:   fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<42xi32>>
23// CHECK-NEXT:   return
24// CHECK-NEXT: }
25
26// Check the data-flow-analysis can detect cases where we aren't sure if memory
27// is freed by the end of the function
28func.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
29  %7 = arith.constant 42 : index
30  %8 = fir.allocmem !fir.array<?xi32>, %7 {uniq_name = "_QFdfa1Earr.alloc"}
31  %9 = fir.load %arg0 : !fir.ref<!fir.logical<4>>
32  %10 = fir.convert %9 : (!fir.logical<4>) -> i1
33  fir.if %10 {
34    fir.freemem %8 : !fir.heap<!fir.array<?xi32>>
35  } else {
36  }
37  return
38}
39// CHECK:      func.func @dfa1(%arg0: !fir.ref<!fir.logical<4>> {fir.bindc_name = "cond"}) {
40// CHECK-NEXT:   %[[C42:.*]] = arith.constant 42 : index
41// CHECK-NEXT:   %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[C42]] {uniq_name = "_QFdfa1Earr.alloc"}
42// CHECK-NEXT:   %[[LOGICAL:.*]] = fir.load %arg0 : !fir.ref<!fir.logical<4>>
43// CHECK-NEXT:   %[[BOOL:.*]] = fir.convert %[[LOGICAL]] : (!fir.logical<4>) -> i1
44// CHECK-NEXT:   fir.if %[[BOOL]] {
45// CHECK-NEXT:     fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
46// CHECK-NEXT:   } else {
47// CHECK-NEXT:   }
48// CHECK-NEXT:   return
49// CHECK-NEXT: }
50
51// Check scf.if
52func.func @dfa2(%arg0: i1) {
53  %a = fir.allocmem !fir.array<1xi8>
54  scf.if %arg0 {
55    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
56  } else {
57  }
58  return
59}
60// CHECK:     func.func @dfa2(%arg0: i1) {
61// CHECK-NEXT:  %[[MEM:.*]] = fir.allocmem !fir.array<1xi8>
62// CHECK-NEXT:  scf.if %arg0 {
63// CHECK-NEXT:    fir.freemem %[[MEM]] : !fir.heap<!fir.array<1xi8>>
64// CHECK-NEXT:  } else {
65// CHECK-NEXT:  }
66// CHECK-NEXT:  return
67// CHECK-NEXT:  }
68
69// Check freemem in both regions
70func.func @dfa3(%arg0: i1) {
71  %a = fir.allocmem !fir.array<1xi8>
72  fir.if %arg0 {
73    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
74  } else {
75    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
76  }
77  return
78}
79// CHECK:     func.func @dfa3(%arg0: i1) {
80// CHECK-NEXT:  %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
81// CHECK-NEXT:  fir.if %arg0 {
82// CHECK-NEXT:  } else {
83// CHECK-NEXT:  }
84// CHECK-NEXT:  return
85// CHECK-NEXT:  }
86
87func.func private @dfa3a_foo(!fir.ref<!fir.array<1xi8>>) -> ()
88func.func private @dfa3a_bar(!fir.ref<!fir.array<1xi8>>) -> ()
89
90// Check freemem in both regions, with other uses
91func.func @dfa3a(%arg0: i1) {
92  %a = fir.allocmem !fir.array<1xi8>
93  fir.if %arg0 {
94    %ref = fir.convert %a : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
95    func.call @dfa3a_foo(%ref) : (!fir.ref<!fir.array<1xi8>>) -> ()
96    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
97  } else {
98    %ref = fir.convert %a : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
99    func.call @dfa3a_bar(%ref) : (!fir.ref<!fir.array<1xi8>>) -> ()
100    fir.freemem %a : !fir.heap<!fir.array<1xi8>>
101  }
102  return
103}
104// CHECK:     func.func @dfa3a(%arg0: i1) {
105// CHECK-NEXT:  %[[MEM:.*]] = fir.alloca !fir.array<1xi8>
106// CHECK-NEXT:  %[[HEAP:.*]] = fir.convert %[[MEM]] : (!fir.ref<!fir.array<1xi8>>) -> !fir.heap<!fir.array<1xi8>>
107// CHECK-NEXT:  fir.if %arg0 {
108// CHECK-NEXT:    %[[REF:.*]] = fir.convert %[[HEAP]] : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
109// CHECK-NEXT:    func.call @dfa3a_foo(%[[REF]])
110// CHECK-NEXT:  } else {
111// CHECK-NEXT:    %[[REF:.*]] = fir.convert %[[HEAP]] : (!fir.heap<!fir.array<1xi8>>) -> !fir.ref<!fir.array<1xi8>>
112// CHECK-NEXT:    func.call @dfa3a_bar(%[[REF]])
113// CHECK-NEXT:  }
114// CHECK-NEXT:  return
115// CHECK-NEXT:  }
116
117// check the alloca is placed after all operands become available
118func.func @placement1() {
119  // do some stuff with other ssa values
120  %1 = arith.constant 1 : index
121  %2 = arith.constant 2 : index
122  %3 = arith.addi %1, %2 : index
123  // operand is now available
124  %4 = fir.allocmem !fir.array<?xi32>, %3
125  // ...
126  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
127  return
128}
129// CHECK:      func.func @placement1() {
130// CHECK-NEXT:   %[[ARG:.*]] = arith.constant 3 : index
131// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[ARG]]
132// CHECK-NEXT:   return
133// CHECK-NEXT: }
134
135// check that if there are no operands, then the alloca is placed early
136func.func @placement2() {
137  // do some stuff with other ssa values
138  %1 = arith.constant 1 : index
139  %2 = arith.constant 2 : index
140  %3 = arith.addi %1, %2 : index
141  %4 = fir.allocmem !fir.array<42xi32>
142  // ...
143  fir.freemem %4 : !fir.heap<!fir.array<42xi32>>
144  return
145}
146// CHECK:      func.func @placement2() {
147// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
148// CHECK-NEXT:   %[[ONE:.*]] = arith.constant 1 : index
149// CHECK-NEXT:   %[[TWO:.*]] = arith.constant 2 : index
150// CHECK-NEXT:   %[[SUM:.*]] = arith.addi %[[ONE]], %[[TWO]] : index
151// CHECK-NEXT:   return
152// CHECK-NEXT: }
153
154// check that stack allocations which must be placed in loops use stacksave
155func.func @placement3() {
156  %c1 = arith.constant 1 : index
157  %c1_i32 = fir.convert %c1 : (index) -> i32
158  %c2 = arith.constant 2 : index
159  %c10 = arith.constant 10 : index
160  %0:2 = fir.do_loop %arg0 = %c1 to %c10 step %c1 iter_args(%arg1 = %c1_i32) -> (index, i32) {
161    %3 = arith.addi %c1, %c2 : index
162    // operand is now available
163    %4 = fir.allocmem !fir.array<?xi32>, %3
164    // ...
165    fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
166    fir.result %3, %c1_i32 : index, i32
167  }
168  return
169}
170// CHECK:      func.func @placement3() {
171// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
172// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
173// CHECK-NEXT:   %[[C2:.*]] = arith.constant 2 : index
174// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
175// CHECK-NEXT:   fir.do_loop
176// CHECK-NEXT:     %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
177// CHECK-NEXT:     %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
178// CHECK-NEXT:     %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[SUM]]
179// CHECK-NEXT:     llvm.intr.stackrestore %[[SP]] : !llvm.ptr
180// CHECK-NEXT:     fir.result
181// CHECK-NEXT:   }
182// CHECK-NEXT:   return
183// CHECK-NEXT: }
184
185// check that stack save/restore are used in CFG loops
186func.func @placement4(%arg0 : i1) {
187  %c1 = arith.constant 1 : index
188  %c1_i32 = fir.convert %c1 : (index) -> i32
189  %c2 = arith.constant 2 : index
190  %c10 = arith.constant 10 : index
191  cf.br ^bb1
192^bb1:
193  %3 = arith.addi %c1, %c2 : index
194  // operand is now available
195  %4 = fir.allocmem !fir.array<?xi32>, %3
196  // ...
197  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
198  cf.cond_br %arg0, ^bb1, ^bb2
199^bb2:
200  return
201}
202// CHECK:      func.func @placement4(%arg0: i1) {
203// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
204// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
205// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
206// CHECK-NEXT:   cf.br ^bb1
207// CHECK-NEXT: ^bb1:
208// CHECK-NEXT:   %[[C3:.*]] = arith.constant 3 : index
209// CHECK-NEXT:   %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
210// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[C3]]
211// CHECK-NEXT:   llvm.intr.stackrestore %[[SP]] : !llvm.ptr
212// CHECK-NEXT:   cf.cond_br %arg0, ^bb1, ^bb2
213// CHECK-NEXT: ^bb2:
214// CHECK-NEXT:   return
215// CHECK-NEXT: }
216
217// check that stacksave is not used when there is an intervening alloca
218func.func @placement5() {
219  %c1 = arith.constant 1 : index
220  %c1_i32 = fir.convert %c1 : (index) -> i32
221  %c2 = arith.constant 2 : index
222  %c10 = arith.constant 10 : index
223  %0:2 = fir.do_loop %arg0 = %c1 to %c10 step %c1 iter_args(%arg1 = %c1_i32) -> (index, i32) {
224    %3 = arith.addi %c1, %c2 : index
225    // operand is now available
226    %4 = fir.allocmem !fir.array<?xi32>, %3
227    %5 = fir.alloca i32
228    fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
229    fir.result %3, %c1_i32 : index, i32
230  }
231  return
232}
233// CHECK:      func.func @placement5() {
234// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
235// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
236// CHECK-NEXT:   %[[C2:.*]] = arith.constant 2 : index
237// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
238// CHECK-NEXT:   fir.do_loop
239// CHECK-NEXT:     %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
240// CHECK-NEXT:     %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[SUM]]
241// CHECK-NEXT:     %[[IDX:.*]] = fir.alloca i32
242// CHECK-NEXT:     fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
243// CHECK-NEXT:     fir.result
244// CHECK-NEXT:   }
245// CHECK-NEXT:   return
246// CHECK-NEXT: }
247
248// check that stack save/restore are not used when the memalloc and freemem are
249// in different blocks
250func.func @placement6(%arg0: i1) {
251  %c1 = arith.constant 1 : index
252  %c1_i32 = fir.convert %c1 : (index) -> i32
253  %c2 = arith.constant 2 : index
254  %c10 = arith.constant 10 : index
255  cf.br ^bb1
256^bb1:
257  %3 = arith.addi %c1, %c2 : index
258  // operand is now available
259  %4 = fir.allocmem !fir.array<?xi32>, %3
260  // ...
261  cf.cond_br %arg0, ^bb2, ^bb3
262^bb2:
263  // ...
264  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
265  cf.br ^bb1
266^bb3:
267  // ...
268  fir.freemem %4 : !fir.heap<!fir.array<?xi32>>
269  cf.br ^bb1
270}
271// CHECK:      func.func @placement6(%arg0: i1) {
272// CHECK-NEXT:   %[[c1:.*]] = arith.constant 1 : index
273// CHECK-NEXT:   %[[c1_i32:.*]] = fir.convert %[[c1]] : (index) -> i32
274// CHECK-NEXT:   %[[c2:.*]] = arith.constant 2 : index
275// CHECK-NEXT:   %[[c10:.*]] = arith.constant 10 : index
276// CHECK-NEXT:   cf.br ^bb1
277// CHECK-NEXT: ^bb1:
278// CHECK-NEXT:   %[[ADD:.*]] = arith.addi %[[c1]], %[[c2]] : index
279// CHECK-NEXT:   %[[MEM:.*]] = fir.allocmem !fir.array<?xi32>, %[[ADD]]
280// CHECK-NEXT:   cf.cond_br %arg0, ^bb2, ^bb3
281// CHECK-NEXT: ^bb2:
282// CHECK-NEXT:   fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
283// CHECK-NEXT:   cf.br ^bb1
284// CHECK-NEXT: ^bb3:
285// CHECK-NEXT:   fir.freemem %[[MEM]] : !fir.heap<!fir.array<?xi32>>
286// CHECK-NEXT:   cf.br ^bb1
287// CHECK-NEXT: }
288
289// Check multiple returns, where the memory is always freed
290func.func @returns(%arg0: i1) {
291  %0 = fir.allocmem !fir.array<42xi32>
292  cf.cond_br %arg0, ^bb1, ^bb2
293^bb1:
294  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
295  return
296^bb2:
297  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
298  return
299}
300// CHECK:      func.func @returns(%[[COND:.*]]: i1) {
301// CHECK-NEXT:   %[[ALLOC:.*]] = fir.alloca !fir.array<42xi32>
302// CHECK-NEXT:   cf.cond_br %[[COND]], ^bb1, ^bb2
303// CHECK-NEXT: ^bb1:
304// CHECK-NEXT:   return
305// CHECK-NEXT: ^bb2:
306// CHECK-NEXT:   return
307// CHECK-NEXT: }
308
309// Check multiple returns, where the memory is not freed on one branch
310func.func @returns2(%arg0: i1) {
311  %0 = fir.allocmem !fir.array<42xi32>
312  cf.cond_br %arg0, ^bb1, ^bb2
313^bb1:
314  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
315  return
316^bb2:
317  return
318}
319// CHECK:      func.func @returns2(%[[COND:.*]]: i1) {
320// CHECK-NEXT:   %[[ALLOC:.*]] = fir.allocmem !fir.array<42xi32>
321// CHECK-NEXT:   cf.cond_br %[[COND]], ^bb1, ^bb2
322// CHECK-NEXT: ^bb1:
323// CHECK-NEXT:   fir.freemem %[[ALLOC]] : !fir.heap<!fir.array<42xi32>>
324// CHECK-NEXT:   return
325// CHECK-NEXT: ^bb2:
326// CHECK-NEXT:   return
327// CHECK-NEXT: }
328
329// Check allocations are not moved outside of an omp region
330func.func @omp_placement1() {
331  omp.sections {
332    omp.section {
333      %mem = fir.allocmem !fir.array<42xi32>
334      fir.freemem %mem : !fir.heap<!fir.array<42xi32>>
335      omp.terminator
336    }
337    omp.terminator
338  }
339  return
340}
341// CHECK:      func.func @omp_placement1() {
342// CHECK-NEXT:   %[[MEM:.*]] = fir.alloca !fir.array<42xi32>
343// CHECK-NEXT:   %[[MEM_CONV:.*]] = fir.convert %[[MEM]] : (!fir.ref<!fir.array<42xi32>>) -> !fir.heap<!fir.array<42xi32>>
344// CHECK-NEXT:   omp.sections {
345// CHECK-NEXT:     omp.section {
346// CHECK-NEXT:       omp.terminator
347// CHECK-NEXT:     }
348// CHECK-NEXT:     omp.terminator
349// CHECK-NEXT:   }
350// CHECK-NEXT:   return
351// CHECK-NEXT: }
352
353// function terminated by stop statement
354func.func @stop_terminator() {
355  %0 = fir.allocmem !fir.array<42xi32>
356  fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
357  %c0_i32 = arith.constant 0 : i32
358  %false = arith.constant false
359  fir.call @_FortranAStopStatement(%c0_i32, %false, %false) : (i32, i1, i1) -> ()
360  fir.unreachable
361}
362// CHECK: func.func @stop_terminator() {
363// CHECK-NEXT: fir.alloca !fir.array<42xi32>
364// CHECK-NEXT:  %[[ZERO:.*]] = arith.constant 0 : i32
365// CHECK-NEXT:  %[[FALSE:.*]] = arith.constant false
366// CHECK-NEXT:  fir.call @_FortranAStopStatement(%[[ZERO]], %[[FALSE]], %[[FALSE]]) : (i32, i1, i1) -> ()
367// CHECK-NEXT:  fir.unreachable
368// CHECK-NEXT: }
369
370
371// check that stack allocations that use fir.declare which must be placed in loops
372// use stacksave
373func.func @placement_loop_declare() {
374  %c1 = arith.constant 1 : index
375  %c1_i32 = fir.convert %c1 : (index) -> i32
376  %c2 = arith.constant 2 : index
377  %c10 = arith.constant 10 : index
378  %0:2 = fir.do_loop %arg0 = %c1 to %c10 step %c1 iter_args(%arg1 = %c1_i32) -> (index, i32) {
379    %3 = arith.addi %c1, %c2 : index
380    // operand is now available
381    %4 = fir.allocmem !fir.array<?xi32>, %3
382    %shape = fir.shape %3 : (index) -> !fir.shape<1>
383    %5 = fir.declare %4(%shape) {uniq_name = "temp"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.heap<!fir.array<?xi32>>
384    // ...
385    fir.freemem %5 : !fir.heap<!fir.array<?xi32>>
386    fir.result %3, %c1_i32 : index, i32
387  }
388  return
389}
390// CHECK:      func.func @placement_loop_declare() {
391// CHECK-NEXT:   %[[C1:.*]] = arith.constant 1 : index
392// CHECK-NEXT:   %[[C1_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
393// CHECK-NEXT:   %[[C2:.*]] = arith.constant 2 : index
394// CHECK-NEXT:   %[[C10:.*]] = arith.constant 10 : index
395// CHECK-NEXT:   fir.do_loop
396// CHECK-NEXT:     %[[SUM:.*]] = arith.addi %[[C1]], %[[C2]] : index
397// CHECK-NEXT:     %[[SP:.*]] = llvm.intr.stacksave : !llvm.ptr
398// CHECK-NEXT:     %[[MEM:.*]] = fir.alloca !fir.array<?xi32>, %[[SUM]]
399// CHECK:          llvm.intr.stackrestore %[[SP]] : !llvm.ptr
400// CHECK-NEXT:     fir.result
401// CHECK-NEXT:   }
402// CHECK-NEXT:   return
403// CHECK-NEXT: }
404
405// Can we look through fir.convert and fir.declare?
406func.func @lookthrough() {
407  %0 = fir.allocmem !fir.array<42xi32>
408  %c42 = arith.constant 42 : index
409  %shape = fir.shape %c42 : (index) -> !fir.shape<1>
410  %1 = fir.declare %0(%shape) {uniq_name = "name"} : (!fir.heap<!fir.array<42xi32>>, !fir.shape<1>) -> !fir.heap<!fir.array<42xi32>>
411  %2 = fir.convert %1 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
412  // use the ref so the converts aren't folded
413  %3 = fir.load %2 : !fir.ref<!fir.array<42xi32>>
414  %4 = fir.convert %2 : (!fir.ref<!fir.array<42xi32>>) -> !fir.heap<!fir.array<42xi32>>
415  fir.freemem %4 : !fir.heap<!fir.array<42xi32>>
416  return
417}
418// CHECK: func.func @lookthrough() {
419// CHECK:     fir.alloca !fir.array<42xi32>
420// CHECK-NOT: fir.freemem
421
422// StackArrays is better to find fir.freemem ops corresponding to fir.allocmem
423// using the same look through mechanism as during the allocation analysis,
424// looking through fir.convert and fir.declare.
425func.func @finding_freemem_in_block() {
426  %c0 = arith.constant 0 : index
427  %c10_i32 = arith.constant 10 : i32
428  %c1_i32 = arith.constant 1 : i32
429  %0 = fir.alloca i32 {bindc_name = "k", uniq_name = "k"}
430  %1 = fir.declare %0 {uniq_name = "k"} : (!fir.ref<i32>) -> !fir.ref<i32>
431  fir.store %c1_i32 to %1 : !fir.ref<i32>
432  cf.br ^bb1
433^bb1:  // 2 preds: ^bb0, ^bb2
434  %2 = fir.load %1 : !fir.ref<i32>
435  %3 = arith.cmpi sle, %2, %c10_i32 : i32
436  cf.cond_br %3, ^bb2, ^bb3
437^bb2:  // pred: ^bb1
438  %4 = fir.declare %1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "x"} : (!fir.ref<i32>) -> !fir.ref<i32>
439  %5 = fir.load %4 : !fir.ref<i32>
440  %6 = fir.convert %5 : (i32) -> index
441  %7 = arith.cmpi sgt, %6, %c0 : index
442  %8 = arith.select %7, %6, %c0 : index
443  %9 = fir.shape %8 : (index) -> !fir.shape<1>
444  %10 = fir.allocmem !fir.array<?xi32>, %8 {bindc_name = ".tmp.expr_result", uniq_name = ""}
445  %11 = fir.convert %10 : (!fir.heap<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
446  %12 = fir.declare %11(%9) {uniq_name = ".tmp.expr_result"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<?xi32>>
447  %13 = fir.embox %12(%9) : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
448  %14 = fir.call @_QPfunc(%1) fastmath<fast> : (!fir.ref<i32>) -> !fir.array<?xi32>
449  fir.save_result %14 to %12(%9) : !fir.array<?xi32>, !fir.ref<!fir.array<?xi32>>, !fir.shape<1>
450  fir.call @_QPsub(%13) fastmath<fast> : (!fir.box<!fir.array<?xi32>>) -> ()
451  %15 = fir.convert %12 : (!fir.ref<!fir.array<?xi32>>) -> !fir.heap<!fir.array<?xi32>>
452  fir.freemem %15 : !fir.heap<!fir.array<?xi32>>
453  %16 = fir.load %1 : !fir.ref<i32>
454  %17 = arith.addi %16, %c1_i32 : i32
455  fir.store %17 to %1 : !fir.ref<i32>
456  cf.br ^bb1
457^bb3:  // pred: ^bb1
458  return
459}
460// CHECK: func.func @finding_freemem_in_block() {
461// CHECK:     fir.alloca !fir.array<?xi32>
462// CHECK-NOT: fir.freemem
463