; ModuleID = 'LFortran'
source_filename = "LFortran"
target datalayout = "..."

%array.1 = type { i32*, i64, i32, i8, i8, i8, i8, i64, [1 x %dimension_descriptor] }
%dimension_descriptor = type { i64, i64, i64 }
%string_descriptor = type <{ i8*, i64 }>
%array.2 = type { float*, i64, i32, i8, i8, i8, i8, i64, [2 x %dimension_descriptor] }

@0 = private unnamed_addr constant [4 x i8] c"arr\00", align 1
@1 = private unnamed_addr constant [22 x i8] c"tests/finalize_01.f90\00", align 1
@2 = private unnamed_addr constant [53 x i8] c"Cannot allocate '%s' because it is already allocated\00", align 1
@3 = private unnamed_addr constant [55 x i8] c"Attempting to allocate already allocated variable '%s'\00", align 1
@__Wrong_allocation = private unnamed_addr constant [51 x i8] c"Attempting to allocate already allocated variable!\00", align 1

define void @__module_finalize_01_mod_ss() {
.entry:
  %0 = call i8* @_lfortran_get_default_allocator()
  %arr_desc = alloca %array.1, align 8
  %arr = alloca %array.1*, align 8
  store %array.1* null, %array.1** %arr, align 8
  %1 = getelementptr %array.1, %array.1* %arr_desc, i32 0, i32 8
  %2 = getelementptr [1 x %dimension_descriptor], [1 x %dimension_descriptor]* %1, i32 0, i32 0
  %3 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %2, i32 0
  %4 = getelementptr %dimension_descriptor, %dimension_descriptor* %3, i32 0, i32 0
  store i64 1, i64* %4, align 8
  %5 = getelementptr %dimension_descriptor, %dimension_descriptor* %3, i32 0, i32 1
  store i64 1, i64* %5, align 8
  %6 = getelementptr %dimension_descriptor, %dimension_descriptor* %3, i32 0, i32 2
  store i64 0, i64* %6, align 8
  %7 = getelementptr %array.1, %array.1* %arr_desc, i32 0, i32 3
  store i8 1, i8* %7, align 1
  %8 = getelementptr %array.1, %array.1* %arr_desc, i32 0, i32 0
  store i32* null, i32** %8, align 8
  store %array.1* %arr_desc, %array.1** %arr, align 8
  %9 = load %array.1*, %array.1** %arr, align 8
  %10 = ptrtoint %array.1* %9 to i64
  %11 = icmp eq i64 %10, 0
  br i1 %11, label %merge_allocated, label %check_data

check_data:                                       ; preds = %.entry
  %12 = getelementptr %array.1, %array.1* %9, i32 0, i32 0
  %13 = load i32*, i32** %12, align 8
  %14 = ptrtoint i32* %13 to i64
  %15 = icmp ne i64 %14, 0
  br label %merge_allocated

merge_allocated:                                  ; preds = %check_data, %.entry
  %is_allocated = phi i1 [ false, %.entry ], [ %15, %check_data ]
  br i1 %is_allocated, label %then, label %ifcont

then:                                             ; preds = %merge_allocated
  %16 = alloca [1 x { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }], align 8
  %17 = alloca [1 x { i8*, i32, i32, i32, i32 }], align 8
  %18 = getelementptr inbounds [1 x { i8*, i32, i32, i32, i32 }], [1 x { i8*, i32, i32, i32, i32 }]* %17, i32 0, i32 0
  %19 = getelementptr { i8*, i32, i32, i32, i32 }, { i8*, i32, i32, i32, i32 }* %18, i32 0, i32 0
  store i8* getelementptr inbounds ([22 x i8], [22 x i8]* @1, i32 0, i32 0), i8** %19, align 8
  %20 = getelementptr { i8*, i32, i32, i32, i32 }, { i8*, i32, i32, i32, i32 }* %18, i32 0, i32 1
  store i32 15, i32* %20, align 4
  %21 = getelementptr { i8*, i32, i32, i32, i32 }, { i8*, i32, i32, i32, i32 }* %18, i32 0, i32 2
  store i32 18, i32* %21, align 4
  %22 = getelementptr { i8*, i32, i32, i32, i32 }, { i8*, i32, i32, i32, i32 }* %18, i32 0, i32 3
  store i32 15, i32* %22, align 4
  %23 = getelementptr { i8*, i32, i32, i32, i32 }, { i8*, i32, i32, i32, i32 }* %18, i32 0, i32 4
  store i32 24, i32* %23, align 4
  %24 = call i8* (i8*, i8*, ...) @_lcompilers_snprintf_alloc(i8* %0, i8* getelementptr inbounds ([53 x i8], [53 x i8]* @2, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0))
  %25 = getelementptr inbounds [1 x { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }], [1 x { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }]* %16, i32 0, i32 0
  %26 = getelementptr [1 x { i8*, i32, i32, i32, i32 }], [1 x { i8*, i32, i32, i32, i32 }]* %17, i32 0, i32 0
  %27 = getelementptr { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }* %25, i32 0, i32 2
  %28 = getelementptr { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }* %25, i32 0, i32 0
  store i1 true, i1* %28, align 1
  %29 = getelementptr { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }* %25, i32 0, i32 1
  store i8* %24, i8** %29, align 8
  store { i8*, i32, i32, i32, i32 }* %26, { i8*, i32, i32, i32, i32 }** %27, align 8
  %30 = getelementptr { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }* %25, i32 0, i32 3
  store i32 1, i32* %30, align 4
  %31 = getelementptr [1 x { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }], [1 x { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }]* %16, i32 0, i32 0
  call void (i8*, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }*, i32, i8*, ...) @_lcompilers_runtime_error(i8* %0, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }* %31, i32 1, i8* getelementptr inbounds ([55 x i8], [55 x i8]* @3, i32 0, i32 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @0, i32 0, i32 0))
  call void @exit(i32 1)
  unreachable

ifcont:                                           ; preds = %merge_allocated
  %32 = load %array.1*, %array.1** %arr, align 8
  %33 = getelementptr %array.1, %array.1* %32, i32 0, i32 7
  store i64 0, i64* %33, align 8
  %34 = getelementptr %array.1, %array.1* %32, i32 0, i32 8
  %35 = getelementptr [1 x %dimension_descriptor], [1 x %dimension_descriptor]* %34, i32 0, i32 0
  %36 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %35, i32 0
  %37 = getelementptr %dimension_descriptor, %dimension_descriptor* %36, i32 0, i32 2
  %38 = getelementptr %dimension_descriptor, %dimension_descriptor* %36, i32 0, i32 0
  %39 = getelementptr %dimension_descriptor, %dimension_descriptor* %36, i32 0, i32 1
  store i64 1, i64* %37, align 8
  store i64 1, i64* %38, align 8
  store i64 10, i64* %39, align 8
  %40 = getelementptr %array.1, %array.1* %32, i32 0, i32 0
  %41 = call i8* @_lfortran_get_default_allocator()
  %42 = call i8* @_lfortran_malloc_alloc(i8* %41, i64 40)
  %43 = bitcast i8* %42 to i32*
  store i32* %43, i32** %40, align 8
  br i1 true, label %then1, label %else

then1:                                            ; preds = %ifcont
  br label %return

unreachable_after_return:                         ; No predecessors!
  br label %ifcont3

else:                                             ; preds = %ifcont
  br label %return

unreachable_after_return2:                        ; No predecessors!
  br label %ifcont3

ifcont3:                                          ; preds = %unreachable_after_return2, %unreachable_after_return
  br label %return

return:                                           ; preds = %ifcont3, %else, %then1
  br label %FINALIZE_SYMTABLE_ss

FINALIZE_SYMTABLE_ss:                             ; preds = %return
  br label %Finalize_Variable_arr

Finalize_Variable_arr:                            ; preds = %FINALIZE_SYMTABLE_ss
  %44 = load %array.1*, %array.1** %arr, align 8
  call void @finalize_allocatable__Array_1_i32(%array.1* %44)
  ret void
}

declare i8* @_lcompilers_snprintf_alloc(i8*, i8*, ...)

declare i8* @_lfortran_get_default_allocator()

declare void @_lcompilers_runtime_error(i8*, { i1, i8*, { i8*, i32, i32, i32, i32 }*, i32 }*, i32, i8*, ...)

declare void @exit(i32)

declare i8* @_lfortran_malloc_alloc(i8*, i64)

define internal void @finalize_allocatable__Array_1_i32(%array.1* %0) {
entry:
  %1 = icmp ne %array.1* %0, null
  br i1 %1, label %is_allocated.then, label %is_allocated.else

is_allocated.then:                                ; preds = %entry
  call void @finalize_descriptorArray_Array_1_i32(%array.1* %0)
  br label %is_allocated.ifcont

is_allocated.else:                                ; preds = %entry
  br label %is_allocated.ifcont

is_allocated.ifcont:                              ; preds = %is_allocated.else, %is_allocated.then
  ret void
}

define internal void @finalize_descriptorArray_Array_1_i32(%array.1* %0) {
entry:
  %1 = call i8* @_lfortran_get_default_allocator()
  %2 = getelementptr %array.1, %array.1* %0, i32 0, i32 0
  %3 = load i32*, i32** %2, align 8
  %4 = bitcast i32* %3 to i8*
  call void @_lfortran_free_alloc(i8* %1, i8* %4)
  ret void
}

declare void @_lfortran_free_alloc(i8*, i8*)

define i32 @main(i32 %0, i8** %1) {
.entry:
  %2 = call i8* @_lfortran_get_default_allocator()
  %arr_desc = alloca %array.1, align 8
  call void @_lpython_call_initial_functions(i32 %0, i8** %1)
  %arr = alloca %array.1*, align 8
  store %array.1* null, %array.1** %arr, align 8
  %3 = getelementptr %array.1, %array.1* %arr_desc, i32 0, i32 8
  %4 = getelementptr [1 x %dimension_descriptor], [1 x %dimension_descriptor]* %3, i32 0, i32 0
  %5 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %4, i32 0
  %6 = getelementptr %dimension_descriptor, %dimension_descriptor* %5, i32 0, i32 0
  store i64 1, i64* %6, align 8
  %7 = getelementptr %dimension_descriptor, %dimension_descriptor* %5, i32 0, i32 1
  store i64 1, i64* %7, align 8
  %8 = getelementptr %dimension_descriptor, %dimension_descriptor* %5, i32 0, i32 2
  store i64 0, i64* %8, align 8
  %9 = getelementptr %array.1, %array.1* %arr_desc, i32 0, i32 3
  store i8 1, i8* %9, align 1
  %10 = getelementptr %array.1, %array.1* %arr_desc, i32 0, i32 0
  store i32* null, i32** %10, align 8
  store %array.1* %arr_desc, %array.1** %arr, align 8
  %str = alloca %string_descriptor, align 8
  store %string_descriptor zeroinitializer, %string_descriptor* %str, align 1
  %11 = getelementptr %string_descriptor, %string_descriptor* %str, i32 0, i32 0
  %12 = load i8*, i8** %11, align 8
  %13 = icmp ne i8* %12, null
  br i1 %13, label %then, label %else

then:                                             ; preds = %.entry
  call void (i8*, ...) @_lcompilers_print_error(i8* getelementptr inbounds ([51 x i8], [51 x i8]* @__Wrong_allocation, i32 0, i32 0))
  call void @exit(i32 1)
  br label %ifcont

else:                                             ; preds = %.entry
  br label %ifcont

ifcont:                                           ; preds = %else, %then
  %14 = getelementptr %string_descriptor, %string_descriptor* %str, i32 0, i32 0
  %15 = call i8* @_lfortran_get_default_allocator()
  %16 = call i8* @_lfortran_malloc_alloc(i8* %15, i64 10)
  store i8* %16, i8** %14, align 8
  %17 = getelementptr %string_descriptor, %string_descriptor* %str, i32 0, i32 1
  store i64 10, i64* %17, align 8
  call void @__module_finalize_01_mod_ss()
  call void @internal_sub()
  br label %return

unreachable_after_return:                         ; No predecessors!
  br label %return

return:                                           ; preds = %unreachable_after_return, %ifcont
  br label %FINALIZE_SYMTABLE_finalize_01

FINALIZE_SYMTABLE_finalize_01:                    ; preds = %return
  br label %Finalize_Variable_arr

Finalize_Variable_arr:                            ; preds = %FINALIZE_SYMTABLE_finalize_01
  %18 = load %array.1*, %array.1** %arr, align 8
  call void @finalize_allocatable__Array_1_i32(%array.1* %18)
  br label %Finalize_Variable_str

Finalize_Variable_str:                            ; preds = %Finalize_Variable_arr
  %19 = getelementptr %string_descriptor, %string_descriptor* %str, i32 0, i32 0
  %20 = load i8*, i8** %19, align 8
  call void @_lfortran_free_alloc(i8* %2, i8* %20)
  call void @_lfortran_internal_alloc_finalize()
  ret i32 0
}

define void @internal_sub() {
.entry:
  %0 = call i8* @_lfortran_get_default_allocator()
  %arr_desc1 = alloca %array.1, align 8
  %arr_desc = alloca %array.2, align 8
  %arr_real = alloca %array.2*, align 8
  store %array.2* null, %array.2** %arr_real, align 8
  %1 = getelementptr %array.2, %array.2* %arr_desc, i32 0, i32 8
  %2 = getelementptr [2 x %dimension_descriptor], [2 x %dimension_descriptor]* %1, i32 0, i32 0
  %3 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %2, i32 0
  %4 = getelementptr %dimension_descriptor, %dimension_descriptor* %3, i32 0, i32 0
  store i64 1, i64* %4, align 8
  %5 = getelementptr %dimension_descriptor, %dimension_descriptor* %3, i32 0, i32 1
  store i64 1, i64* %5, align 8
  %6 = getelementptr %dimension_descriptor, %dimension_descriptor* %3, i32 0, i32 2
  store i64 0, i64* %6, align 8
  %7 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %2, i32 1
  %8 = getelementptr %dimension_descriptor, %dimension_descriptor* %7, i32 0, i32 0
  store i64 1, i64* %8, align 8
  %9 = getelementptr %dimension_descriptor, %dimension_descriptor* %7, i32 0, i32 1
  store i64 1, i64* %9, align 8
  %10 = getelementptr %dimension_descriptor, %dimension_descriptor* %7, i32 0, i32 2
  store i64 0, i64* %10, align 8
  %11 = getelementptr %array.2, %array.2* %arr_desc, i32 0, i32 3
  store i8 2, i8* %11, align 1
  %12 = getelementptr %array.2, %array.2* %arr_desc, i32 0, i32 0
  store float* null, float** %12, align 8
  store %array.2* %arr_desc, %array.2** %arr_real, align 8
  %str = alloca %string_descriptor, align 8
  store %string_descriptor zeroinitializer, %string_descriptor* %str, align 1
  br label %bl.start

bl.start:                                         ; preds = %.entry
  %13 = call i8* @llvm.stacksave()
  %arr_in_block = alloca %array.1*, align 8
  store %array.1* null, %array.1** %arr_in_block, align 8
  %14 = getelementptr %array.1, %array.1* %arr_desc1, i32 0, i32 8
  %15 = getelementptr [1 x %dimension_descriptor], [1 x %dimension_descriptor]* %14, i32 0, i32 0
  %16 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %15, i32 0
  %17 = getelementptr %dimension_descriptor, %dimension_descriptor* %16, i32 0, i32 0
  store i64 1, i64* %17, align 8
  %18 = getelementptr %dimension_descriptor, %dimension_descriptor* %16, i32 0, i32 1
  store i64 1, i64* %18, align 8
  %19 = getelementptr %dimension_descriptor, %dimension_descriptor* %16, i32 0, i32 2
  store i64 0, i64* %19, align 8
  %20 = getelementptr %array.1, %array.1* %arr_desc1, i32 0, i32 3
  store i8 1, i8* %20, align 1
  %21 = getelementptr %array.1, %array.1* %arr_desc1, i32 0, i32 0
  store i32* null, i32** %21, align 8
  store %array.1* %arr_desc1, %array.1** %arr_in_block, align 8
  br label %bl.end

unreachable_after_exit:                           ; No predecessors!
  br label %return

unreachable_after_return:                         ; No predecessors!
  br label %bl.end

bl.end:                                           ; preds = %unreachable_after_return, %bl.start
  br label %FINALIZE_SYMTABLE_bl

FINALIZE_SYMTABLE_bl:                             ; preds = %bl.end
  br label %Finalize_Variable_arr_in_block

Finalize_Variable_arr_in_block:                   ; preds = %FINALIZE_SYMTABLE_bl
  %22 = load %array.1*, %array.1** %arr_in_block, align 8
  call void @finalize_allocatable__Array_1_i32(%array.1* %22)
  call void @llvm.stackrestore(i8* %13)
  br label %loop.head

loop.head:                                        ; preds = %unreachable_after_return2, %Finalize_Variable_arr_in_block
  br i1 true, label %loop.body, label %loop.end

loop.body:                                        ; preds = %loop.head
  br label %return

unreachable_after_return2:                        ; No predecessors!
  br label %loop.head

loop.end:                                         ; preds = %loop.head
  br label %return

return:                                           ; preds = %loop.end, %loop.body, %unreachable_after_exit
  br label %FINALIZE_SYMTABLE_internal_sub

FINALIZE_SYMTABLE_internal_sub:                   ; preds = %return
  br label %Finalize_Variable_arr_real

Finalize_Variable_arr_real:                       ; preds = %FINALIZE_SYMTABLE_internal_sub
  %23 = load %array.2*, %array.2** %arr_real, align 8
  call void @finalize_allocatable__Array_2_r32(%array.2* %23)
  br label %Finalize_Variable_str

Finalize_Variable_str:                            ; preds = %Finalize_Variable_arr_real
  %24 = getelementptr %string_descriptor, %string_descriptor* %str, i32 0, i32 0
  %25 = load i8*, i8** %24, align 8
  call void @_lfortran_free_alloc(i8* %0, i8* %25)
  ret void
}

; Function Attrs: nounwind
declare i8* @llvm.stacksave() #0

; Function Attrs: nounwind
declare void @llvm.stackrestore(i8*) #0

define internal void @finalize_allocatable__Array_2_r32(%array.2* %0) {
entry:
  %1 = icmp ne %array.2* %0, null
  br i1 %1, label %is_allocated.then, label %is_allocated.else

is_allocated.then:                                ; preds = %entry
  call void @finalize_descriptorArray_Array_2_r32(%array.2* %0)
  br label %is_allocated.ifcont

is_allocated.else:                                ; preds = %entry
  br label %is_allocated.ifcont

is_allocated.ifcont:                              ; preds = %is_allocated.else, %is_allocated.then
  ret void
}

define internal void @finalize_descriptorArray_Array_2_r32(%array.2* %0) {
entry:
  %1 = call i8* @_lfortran_get_default_allocator()
  %2 = getelementptr %array.2, %array.2* %0, i32 0, i32 0
  %3 = load float*, float** %2, align 8
  %4 = bitcast float* %3 to i8*
  call void @_lfortran_free_alloc(i8* %1, i8* %4)
  ret void
}

declare void @_lpython_call_initial_functions(i32, i8**)

declare void @_lcompilers_print_error(i8*, ...)

declare void @_lfortran_internal_alloc_finalize()

attributes #0 = { nounwind }
