diff --git a/flang/test/Lower/allocatable-globals.f90 b/flang/test/Lower/allocatable-globals.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/allocatable-globals.f90 @@ -0,0 +1,72 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s +! RUN: bbc -emit-fir -use-alloc-runtime %s -o - | FileCheck %s + +! Test global allocatable definition lowering + +! CHECK-LABEL: fir.global @_QMmod_allocatablesEc : !fir.box>>> { + ! CHECK-DAG: %[[modcNullAddr:.*]] = fir.zero_bits !fir.heap>> + ! CHECK-DAG: %[[modcShape:.*]] = fir.shape %c0{{.*}} : (index) -> !fir.shape<1> + ! CHECK: %[[modcInitBox:.*]] = fir.embox %[[modcNullAddr]](%[[modcShape]]) : (!fir.heap>>, !fir.shape<1>) -> !fir.box>>> + ! CHECK: fir.has_value %[[modcInitBox]] : !fir.box>>> + +module mod_allocatables + character(10), allocatable :: c(:) + end module + + ! CHECK-LABEL: func @_QPtest_mod_allocatables() + subroutine test_mod_allocatables() + use mod_allocatables, only: c + ! CHECK: fir.address_of(@_QMmod_allocatablesEc) : !fir.ref>>>> + call bar(c(1)) + end subroutine + + + ! CHECK-LABEL: func @_QPtest_globals() + subroutine test_globals() + integer, allocatable :: gx, gy(:, :) + save :: gx, gy + ! CHECK-DAG: fir.address_of(@_QFtest_globalsEgx) : !fir.ref>> + ! CHECK-DAG: fir.address_of(@_QFtest_globalsEgy) : !fir.ref>>> + character(:), allocatable :: gc1, gc2(:, :) + character(10), allocatable :: gc3, gc4(:, :) + save :: gc1, gc2, gc3, gc4 + ! CHECK-DAG: fir.address_of(@_QFtest_globalsEgc1) : !fir.ref>>> + ! CHECK-DAG: fir.address_of(@_QFtest_globalsEgc2) : !fir.ref>>>> + ! CHECK-DAG: fir.address_of(@_QFtest_globalsEgc3) : !fir.ref>>> + ! CHECK-DAG: fir.address_of(@_QFtest_globalsEgc4) : !fir.ref>>>> + allocate(gx, gy(20, 30), gc3, gc4(40, 50)) + allocate(character(15):: gc1, gc2(60, 70)) + end subroutine + + ! CHECK-LABEL: fir.global internal @_QFtest_globalsEgc1 : !fir.box>> + ! CHECK-DAG: %[[gc1NullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK: %[[gc1InitBox:.*]] = fir.embox %[[gc1NullAddr]] typeparams %c0{{.*}} : (!fir.heap>, index) -> !fir.box>> + ! CHECK: fir.has_value %[[gc1InitBox]] : !fir.box>> + + ! CHECK-LABEL: fir.global internal @_QFtest_globalsEgc2 : !fir.box>>> + ! CHECK-DAG: %[[gc2NullAddr:.*]] = fir.zero_bits !fir.heap>> + ! CHECK-DAG: %[[gc2NullShape:.*]] = fir.shape %c0{{.*}}, %c0{{.*}} : (index, index) -> !fir.shape<2> + ! CHECK: %[[gc2InitBox:.*]] = fir.embox %[[gc2NullAddr]](%[[gc2NullShape]]) typeparams %c0{{.*}} : (!fir.heap>>, !fir.shape<2>, index) -> !fir.box>>> + ! CHECK: fir.has_value %[[gc2InitBox]] : !fir.box>>> + + ! CHECK-LABEL: fir.global internal @_QFtest_globalsEgc3 : !fir.box>> + ! CHECK-DAG: %[[gc3NullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK: %[[gc3InitBox:.*]] = fir.embox %[[gc3NullAddr]] : (!fir.heap>) -> !fir.box>> + ! CHECK: fir.has_value %[[gc3InitBox]] : !fir.box>> + + ! CHECK-LABEL: fir.global internal @_QFtest_globalsEgc4 : !fir.box>>> + ! CHECK-DAG: %[[gc4NullAddr:.*]] = fir.zero_bits !fir.heap>> + ! CHECK-DAG: %[[gc4NullShape:.*]] = fir.shape %c0{{.*}}, %c0{{.*}} : (index, index) -> !fir.shape<2> + ! CHECK: %[[gc4InitBox:.*]] = fir.embox %[[gc4NullAddr]](%[[gc4NullShape]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.box>>> + ! CHECK: fir.has_value %[[gc4InitBox]] : !fir.box>>> + + ! CHECK-LABEL: fir.global internal @_QFtest_globalsEgx : !fir.box> + ! CHECK: %[[gxNullAddr:.*]] = fir.zero_bits !fir.heap + ! CHECK: %[[gxInitBox:.*]] = fir.embox %0 : (!fir.heap) -> !fir.box> + ! CHECK: fir.has_value %[[gxInitBox]] : !fir.box> + + ! CHECK-LABEL: fir.global internal @_QFtest_globalsEgy : !fir.box>> { + ! CHECK-DAG: %[[gyNullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK-DAG: %[[gyShape:.*]] = fir.shape %c0{{.*}}, %c0{{.*}} : (index, index) -> !fir.shape<2> + ! CHECK: %[[gyInitBox:.*]] = fir.embox %[[gyNullAddr]](%[[gyShape]]) : (!fir.heap>, !fir.shape<2>) -> !fir.box>> + ! CHECK: fir.has_value %[[gyInitBox]] : !fir.box>> diff --git a/flang/test/Lower/allocatable-runtime.f90 b/flang/test/Lower/allocatable-runtime.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/allocatable-runtime.f90 @@ -0,0 +1,159 @@ +! RUN: bbc -emit-fir -use-alloc-runtime %s -o - | FileCheck %s + +! Test lowering of allocatables using runtime for allocate/deallcoate statements. +! CHECK-LABEL: _QPfoo +subroutine foo() + real, allocatable :: x(:), y(:, :), z + ! CHECK: %[[xBoxAddr:.*]] = fir.alloca !fir.box>> {{{.*}}uniq_name = "_QFfooEx"} + ! CHECK-DAG: %[[xNullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK-DAG: %[[xNullShape:.*]] = fir.shape %c0{{.*}} : (index) -> !fir.shape<1> + ! CHECK: %[[xInitEmbox:.*]] = fir.embox %[[xNullAddr]](%[[xNullShape]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box>> + ! CHECK: fir.store %[[xInitEmbox]] to %[[xBoxAddr]] : !fir.ref>>> + + ! CHECK: %[[yBoxAddr:.*]] = fir.alloca !fir.box>> {{{.*}}uniq_name = "_QFfooEy"} + ! CHECK-DAG: %[[yNullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK-DAG: %[[yNullShape:.*]] = fir.shape %c0{{.*}}, %c0{{.*}} : (index, index) -> !fir.shape<2> + ! CHECK: %[[yInitEmbox:.*]] = fir.embox %[[yNullAddr]](%[[yNullShape]]) : (!fir.heap>, !fir.shape<2>) -> !fir.box>> + ! CHECK: fir.store %[[yInitEmbox]] to %[[yBoxAddr]] : !fir.ref>>> + + ! CHECK: %[[zBoxAddr:.*]] = fir.alloca !fir.box> {{{.*}}uniq_name = "_QFfooEz"} + ! CHECK: %[[zNullAddr:.*]] = fir.zero_bits !fir.heap + ! CHECK: %[[zInitEmbox:.*]] = fir.embox %[[zNullAddr]] : (!fir.heap) -> !fir.box> + ! CHECK: fir.store %[[zInitEmbox]] to %[[zBoxAddr]] : !fir.ref>> + + allocate(x(42:100), y(43:50, 51), z) + ! CHECK-DAG: %[[errMsg:.*]] = fir.absent !fir.box + ! CHECK-DAG: %[[xlb:.*]] = arith.constant 42 : i32 + ! CHECK-DAG: %[[xub:.*]] = arith.constant 100 : i32 + ! CHECK-DAG: %[[xBoxCast2:.*]] = fir.convert %[[xBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK-DAG: %[[xlbCast:.*]] = fir.convert %[[xlb]] : (i32) -> i64 + ! CHECK-DAG: %[[xubCast:.*]] = fir.convert %[[xub]] : (i32) -> i64 + ! CHECK: fir.call @{{.*}}AllocatableSetBounds(%[[xBoxCast2]], %c0{{.*}}, %[[xlbCast]], %[[xubCast]]) : (!fir.ref>, i32, i64, i64) -> none + ! CHECK-DAG: %[[xBoxCast3:.*]] = fir.convert %[[xBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK-DAG: %[[sourceFile:.*]] = fir.convert %{{.*}} -> !fir.ref + ! CHECK: fir.call @{{.*}}AllocatableAllocate(%[[xBoxCast3]], %false{{.*}}, %[[errMsg]], %[[sourceFile]], %{{.*}}) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 + + ! Simply check that we are emitting the right numebr of set bound for y and z. Otherwise, this is just like x. + ! CHECK: fir.convert %[[yBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableSetBounds + ! CHECK: fir.call @{{.*}}AllocatableSetBounds + ! CHECK: fir.call @{{.*}}AllocatableAllocate + ! CHECK: %[[zBoxCast:.*]] = fir.convert %[[zBoxAddr]] : (!fir.ref>>) -> !fir.ref> + ! CHECK-NOT: fir.call @{{.*}}AllocatableSetBounds + ! CHECK: fir.call @{{.*}}AllocatableAllocate + + ! Check that y descriptor is read when referencing it. + ! CHECK: %[[yBoxLoad:.*]] = fir.load %[[yBoxAddr]] : !fir.ref>>> + ! CHECK: %[[yBounds1:.*]]:3 = fir.box_dims %[[yBoxLoad]], %c0{{.*}} : (!fir.box>>, index) -> (index, index, index) + ! CHECK: %[[yBounds2:.*]]:3 = fir.box_dims %[[yBoxLoad]], %c1{{.*}} : (!fir.box>>, index) -> (index, index, index) + ! CHECK: %[[yAddr:.*]] = fir.box_addr %[[yBoxLoad]] : (!fir.box>>) -> !fir.heap> + print *, x, y(45, 46), z + + deallocate(x, y, z) + ! CHECK: %[[xBoxCast4:.*]] = fir.convert %[[xBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableDeallocate(%[[xBoxCast4]], {{.*}}) + ! CHECK: %[[yBoxCast4:.*]] = fir.convert %[[yBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableDeallocate(%[[yBoxCast4]], {{.*}}) + ! CHECK: %[[zBoxCast4:.*]] = fir.convert %[[zBoxAddr]] : (!fir.ref>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableDeallocate(%[[zBoxCast4]], {{.*}}) + end subroutine + + ! test lowering of character allocatables + ! CHECK-LABEL: _QPchar_deferred( + subroutine char_deferred(n) + integer :: n + character(:), allocatable :: scalar, array(:) + ! CHECK-DAG: %[[sBoxAddr:.*]] = fir.alloca !fir.box>> {{{.*}}uniq_name = "_QFchar_deferredEscalar"} + ! CHECK-DAG: %[[sNullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK-DAG: %[[sInitBox:.*]] = fir.embox %[[sNullAddr]] typeparams %c0{{.*}} : (!fir.heap>, index) -> !fir.box>> + ! CHECK-DAG: fir.store %[[sInitBox]] to %[[sBoxAddr]] : !fir.ref>>> + + ! CHECK-DAG: %[[aBoxAddr:.*]] = fir.alloca !fir.box>>> {{{.*}}uniq_name = "_QFchar_deferredEarray"} + ! CHECK-DAG: %[[aNullAddr:.*]] = fir.zero_bits !fir.heap>> + ! CHECK-DAG: %[[aNullShape:.*]] = fir.shape %c0{{.*}} : (index) -> !fir.shape<1> + ! CHECK-DAG: %[[aInitBox:.*]] = fir.embox %[[aNullAddr]](%[[aNullShape]]) typeparams %c0{{.*}} : (!fir.heap>>, !fir.shape<1>, index) -> !fir.box>>> + ! CHECK-DAG: fir.store %[[aInitBox]] to %[[aBoxAddr]] : !fir.ref>>>> + + allocate(character(10):: scalar, array(30)) + ! CHECK-DAG: %[[sBoxCast1:.*]] = fir.convert %[[sBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK-DAG: %[[ten1:.*]] = fir.convert %c10{{.*}} : (i32) -> i64 + ! CHECK: fir.call @{{.*}}AllocatableInitCharacter(%[[sBoxCast1]], %[[ten1]], %c1{{.*}}, %c0{{.*}}, %c0{{.*}}) + ! CHECK-NOT: AllocatableSetBounds + ! CHECK: %[[sBoxCast2:.*]] = fir.convert %[[sBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableAllocate(%[[sBoxCast2]] + + ! CHECK-DAG: %[[aBoxCast1:.*]] = fir.convert %[[aBoxAddr]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK-DAG: %[[ten2:.*]] = fir.convert %c10{{.*}} : (i32) -> i64 + ! CHECK: fir.call @{{.*}}AllocatableInitCharacter(%[[aBoxCast1]], %[[ten2]], %c1{{.*}}, %c1{{.*}}, %c0{{.*}}) + ! CHECK: %[[aBoxCast2:.*]] = fir.convert %[[aBoxAddr]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableSetBounds(%[[aBoxCast2]] + ! CHECK: %[[aBoxCast3:.*]] = fir.convert %[[aBoxAddr]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableAllocate(%[[aBoxCast3]] + + deallocate(scalar, array) + ! CHECK: %[[sBoxCast3:.*]] = fir.convert %[[sBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableDeallocate(%[[sBoxCast3]] + ! CHECK: %[[aBoxCast4:.*]] = fir.convert %[[aBoxAddr]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableDeallocate(%[[aBoxCast4]] + + ! only testing that the correct length is set in the descriptor. + allocate(character(n):: scalar, array(40)) + ! CHECK: %[[n:.*]] = fir.load %arg0 : !fir.ref + ! CHECK-DAG: %[[ncast1:.*]] = fir.convert %[[n]] : (i32) -> i64 + ! CHECK-DAG: %[[sBoxCast4:.*]] = fir.convert %[[sBoxAddr]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableInitCharacter(%[[sBoxCast4]], %[[ncast1]], %c1{{.*}}, %c0{{.*}}, %c0{{.*}}) + ! CHECK-DAG: %[[ncast2:.*]] = fir.convert %[[n]] : (i32) -> i64 + ! CHECK-DAG: %[[aBoxCast5:.*]] = fir.convert %[[aBoxAddr]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: fir.call @{{.*}}AllocatableInitCharacter(%[[aBoxCast5]], %[[ncast2]], %c1{{.*}}, %c1{{.*}}, %c0{{.*}}) + end subroutine + + ! CHECK-LABEL: _QPchar_explicit_cst( + subroutine char_explicit_cst(n) + integer :: n + character(10), allocatable :: scalar, array(:) + ! CHECK-DAG: %[[sBoxAddr:.*]] = fir.alloca !fir.box>> {{{.*}}uniq_name = "_QFchar_explicit_cstEscalar"} + ! CHECK-DAG: %[[sNullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK-DAG: %[[sInitBox:.*]] = fir.embox %[[sNullAddr]] : (!fir.heap>) -> !fir.box>> + ! CHECK-DAG: fir.store %[[sInitBox]] to %[[sBoxAddr]] : !fir.ref>>> + + ! CHECK-DAG: %[[aBoxAddr:.*]] = fir.alloca !fir.box>>> {{{.*}}uniq_name = "_QFchar_explicit_cstEarray"} + ! CHECK-DAG: %[[aNullAddr:.*]] = fir.zero_bits !fir.heap>> + ! CHECK-DAG: %[[aNullShape:.*]] = fir.shape %c0{{.*}} : (index) -> !fir.shape<1> + ! CHECK-DAG: %[[aInitBox:.*]] = fir.embox %[[aNullAddr]](%[[aNullShape]]) : (!fir.heap>>, !fir.shape<1>) -> !fir.box>>> + ! CHECK-DAG: fir.store %[[aInitBox]] to %[[aBoxAddr]] : !fir.ref>>>> + allocate(scalar, array(20)) + ! CHECK-NOT: AllocatableInitCharacter + ! CHECK: AllocatableAllocate + ! CHECK-NOT: AllocatableInitCharacter + ! CHECK: AllocatableAllocate + deallocate(scalar, array) + ! CHECK: AllocatableDeallocate + ! CHECK: AllocatableDeallocate + end subroutine + + ! CHECK-LABEL: _QPchar_explicit_dyn( + subroutine char_explicit_dyn(n, l1, l2) + integer :: n, l1, l2 + character(l1), allocatable :: scalar + ! CHECK-DAG: %[[l1:.*]] = fir.load %arg1 : !fir.ref + ! CHECK-DAG: %[[sBoxAddr:.*]] = fir.alloca !fir.box>> {{{.*}}uniq_name = "_QFchar_explicit_dynEscalar"} + ! CHECK-DAG: %[[sNullAddr:.*]] = fir.zero_bits !fir.heap> + ! CHECK-DAG: %[[sInitBox:.*]] = fir.embox %[[sNullAddr]] typeparams %[[l1]] : (!fir.heap>, i32) -> !fir.box>> + ! CHECK-DAG: fir.store %[[sInitBox]] to %[[sBoxAddr]] : !fir.ref>>> + + character(l2), allocatable :: array(:) + ! CHECK-DAG: %[[l2:.*]] = fir.load %arg2 : !fir.ref + ! CHECK-DAG: %[[aBoxAddr:.*]] = fir.alloca !fir.box>>> {{{.*}}uniq_name = "_QFchar_explicit_dynEarray"} + ! CHECK-DAG: %[[aNullAddr:.*]] = fir.zero_bits !fir.heap>> + ! CHECK-DAG: %[[aNullShape:.*]] = fir.shape %c0{{.*}} : (index) -> !fir.shape<1> + ! CHECK-DAG: %[[aInitBox:.*]] = fir.embox %[[aNullAddr]](%[[aNullShape]]) typeparams %[[l2]] : (!fir.heap>>, !fir.shape<1>, i32) -> !fir.box>>> + ! CHECK-DAG: fir.store %[[aInitBox]] to %[[aBoxAddr]] : !fir.ref>>>> + allocate(scalar, array(20)) + ! CHECK-NOT: AllocatableInitCharacter + ! CHECK: AllocatableAllocate + ! CHECK-NOT: AllocatableInitCharacter + ! CHECK: AllocatableAllocate + deallocate(scalar, array) + ! CHECK: AllocatableDeallocate + ! CHECK: AllocatableDeallocate + end subroutine