diff options
author | jeanPerier <jperier@nvidia.com> | 2024-04-08 10:22:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-08 10:22:44 +0200 |
commit | 6a7da2e30dc38ba92875bfe1da5520c950bab1e3 (patch) | |
tree | 2c30d6b842c1360765dbd8ea743344bc2560021c | |
parent | 0bfea40101c10f80ee35d7fbfd4459e98cdb289c (diff) |
[flang] Fix source allocation to explicit length after deferred length object (#87785)
Flang supports source allocation to allocatable or pointers with a non
deferred length that do not match the source length. This documented at:
https://github.com/llvm/llvm-project/blob/9708d0900311503aa4685d6810d8caf0412e15d7/flang/docs/Extensions.md?plain=1#L312
The current lowering code was bugged when such explicit length allocate
object appeared after a deferred length object in the source allocation
list:
Since "lenParams" had been computed when generating allocation of the
deferred length object, the call to genSetDeferredLengthParameters was
not a no-op on when lowering the explicit length allocation, and the
explicit length was overridden with the source length.
The output of the program added in test was:
```
ZZheZZ
ZZhelloZZ
ZZhelloZZ
```
Instead of:
```
ZZheZZ
ZZhelloZZ
ZZhello ZZ
```
Skip genSetDeferredLengthParameters when the allocate object has non
deferred length.
-rw-r--r-- | flang/lib/Lower/Allocatable.cpp | 8 | ||||
-rw-r--r-- | flang/test/Lower/allocate-source-allocatables-2.f90 | 49 |
2 files changed, 54 insertions, 3 deletions
diff --git a/flang/lib/Lower/Allocatable.cpp b/flang/lib/Lower/Allocatable.cpp index 3557ea93e138..09180518ea41 100644 --- a/flang/lib/Lower/Allocatable.cpp +++ b/flang/lib/Lower/Allocatable.cpp @@ -588,13 +588,15 @@ private: TODO(loc, "coarray: allocation of a coarray object"); // Set length of the allocate object if it has. Otherwise, get the length // from source for the deferred length parameter. - if (lenParams.empty() && box.isCharacter() && - !box.hasNonDeferredLenParams()) + const bool isDeferredLengthCharacter = + box.isCharacter() && !box.hasNonDeferredLenParams(); + if (lenParams.empty() && isDeferredLengthCharacter) lenParams.push_back(fir::factory::readCharLen(builder, loc, exv)); if (!isSource || alloc.type.IsPolymorphic()) genRuntimeAllocateApplyMold(builder, loc, box, exv, alloc.getSymbol().Rank()); - genSetDeferredLengthParameters(alloc, box); + if (isDeferredLengthCharacter) + genSetDeferredLengthParameters(alloc, box); genAllocateObjectBounds(alloc, box); mlir::Value stat; if (isSource) diff --git a/flang/test/Lower/allocate-source-allocatables-2.f90 b/flang/test/Lower/allocate-source-allocatables-2.f90 new file mode 100644 index 000000000000..39b9f04a5f67 --- /dev/null +++ b/flang/test/Lower/allocate-source-allocatables-2.f90 @@ -0,0 +1,49 @@ +! RUN: bbc -emit-hlfir %s -o - | FileCheck %s +! Test lowering of extension of SOURCE allocation (non deferred length +! of character allocate-object need not to match the SOURCE length, truncation +! and padding are performed instead as in assignments). + +subroutine test() +! CHECK-LABEL: func.func @_QPtest() { +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}} {{.*}}Ec_deferred +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_6:.*]] {{.*}}Ec_longer +! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_11:.*]] {{.*}}Ec_shorter +! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_16:.*]] {{{.*}}Ec_source + character(5) :: c_source = "hello" + character(2), allocatable :: c_shorter + character(:), allocatable :: c_deferred + character(7), allocatable :: c_longer +! CHECK: %[[VAL_18:.*]] = arith.constant false +! CHECK: %[[VAL_22:.*]] = fir.embox %[[VAL_17]]#1 : (!fir.ref<!fir.char<1,5>>) -> !fir.box<!fir.char<1,5>> + +! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_14]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,2>>>>) -> !fir.ref<!fir.box<none>> +! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_22]] : (!fir.box<!fir.char<1,5>>) -> !fir.box<none> +! CHECK: %[[VAL_26:.*]] = fir.call @_FortranAAllocatableAllocateSource(%[[VAL_23]], %[[VAL_24]], %[[VAL_18]] + +! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_4]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>>) -> !fir.ref<!fir.box<none>> +! CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_16]] : (index) -> i64 +! CHECK: %[[VAL_29:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_30:.*]] = arith.constant 0 : i32 +! CHECK: %[[VAL_31:.*]] = arith.constant 0 : i32 +! CHECK: %[[VAL_32:.*]] = fir.call @_FortranAAllocatableInitCharacterForAllocate(%[[VAL_27]], %[[VAL_28]], %[[VAL_29]], %[[VAL_30]], %[[VAL_31]] +! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_4]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>>) -> !fir.ref<!fir.box<none>> +! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_22]] : (!fir.box<!fir.char<1,5>>) -> !fir.box<none> +! CHECK: %[[VAL_36:.*]] = fir.call @_FortranAAllocatableAllocateSource(%[[VAL_33]], %[[VAL_34]], %[[VAL_18]], + +! CHECK-NOT: AllocatableInitCharacterForAllocate +! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_9]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,7>>>>) -> !fir.ref<!fir.box<none>> +! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_22]] : (!fir.box<!fir.char<1,5>>) -> !fir.box<none> +! CHECK: %[[VAL_40:.*]] = fir.call @_FortranAAllocatableAllocateSource(%[[VAL_37]], %[[VAL_38]], %[[VAL_18]], + allocate(c_shorter, c_deferred, c_longer, source=c_source) + +! Expect at runtime: +! ZZheZZ +! ZZhelloZZ +! ZZhello ZZ + write(*,"('ZZ',A,'ZZ')") c_shorter + write(*,"('ZZ',A,'ZZ')") c_deferred + write(*,"('ZZ',A,'ZZ')") c_longer +end subroutine + + call test() +end |