Skip to content

Commit 8c12707

Browse files
authored
[flang] Fix issues with STORAGE_SIZE and characters (#67561)
Semantics was replacing storage_size(func()) by the length specification expression of func result (if any), which brought meaningless symbols. Update FunctionRef::GetType to not copy its length parameter from the procedure designator symbol if it is not a constant expression. Note that the deferred aspect can and must be preserved because it matters for POINTER function results (semantics test added to ensure this). Update lowering code to deal with characters in storage_size: simply always call createBox to ensure the BoxEleSizeOp is legal. This will take care of dereferencing pointers/allocatables if needed (what the load was intended for in the previous code).
1 parent db777db commit 8c12707

File tree

7 files changed

+112
-6
lines changed

7 files changed

+112
-6
lines changed

flang/include/flang/Evaluate/call.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,17 @@ template <typename A> class FunctionRef : public ProcedureRef {
268268
FunctionRef(ProcedureDesignator &&p, ActualArguments &&a)
269269
: ProcedureRef{std::move(p), std::move(a)} {}
270270

271-
std::optional<DynamicType> GetType() const { return proc_.GetType(); }
271+
std::optional<DynamicType> GetType() const {
272+
if (auto type{proc_.GetType()}) {
273+
// TODO: Non constant explicit length parameters of PDTs result should
274+
// likely be dropped too. This is not as easy as for characters since some
275+
// long lived DerivedTypeSpec pointer would need to be created here. It is
276+
// not clear if this is causing any issue so far since the storage size of
277+
// PDTs is independent of length parameters.
278+
return type->DropNonConstantCharacterLength();
279+
}
280+
return std::nullopt;
281+
}
272282
};
273283
} // namespace Fortran::evaluate
274284
#endif // FORTRAN_EVALUATE_CALL_H_

flang/include/flang/Evaluate/type.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,12 @@ class DynamicType {
231231
}
232232
}
233233

234+
// Get a copy of this dynamic type where charLengthParamValue_ is reset if it
235+
// is not a constant expression. This avoids propagating symbol references in
236+
// scopes where they do not belong. Returns the type unmodified if it is not
237+
// a character or if the length is not explicit.
238+
DynamicType DropNonConstantCharacterLength() const;
239+
234240
private:
235241
// Special kind codes are used to distinguish the following Fortran types.
236242
enum SpecialKind {

flang/lib/Evaluate/type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,4 +836,15 @@ bool IsCUDAIntrinsicType(const DynamicType &type) {
836836
}
837837
}
838838

839+
DynamicType DynamicType::DropNonConstantCharacterLength() const {
840+
if (charLengthParamValue_ && charLengthParamValue_->isExplicit()) {
841+
if (std::optional<std::int64_t> len{knownLength()}) {
842+
return DynamicType(kind_, *len);
843+
} else {
844+
return DynamicType(category_, kind_);
845+
}
846+
}
847+
return *this;
848+
}
849+
839850
} // namespace Fortran::evaluate

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5284,11 +5284,8 @@ IntrinsicLibrary::genStorageSize(mlir::Type resultType,
52845284
builder.getKindMap().getIntegerBitsize(fir::toInt(constOp)));
52855285
}
52865286

5287-
if (args[0].getBoxOf<fir::PolymorphicValue>()) {
5288-
box = builder.createBox(loc, args[0], /*isPolymorphic=*/true);
5289-
} else if (box.getType().isa<fir::ReferenceType>()) {
5290-
box = builder.create<fir::LoadOp>(loc, box);
5291-
}
5287+
box = builder.createBox(loc, args[0],
5288+
/*isPolymorphic=*/args[0].isPolymorphic());
52925289
mlir::Value eleSize = builder.create<fir::BoxEleSizeOp>(loc, kindTy, box);
52935290
mlir::Value c8 = builder.createIntegerConstant(loc, kindTy, 8);
52945291
return builder.create<mlir::arith::MulIOp>(loc, eleSize, c8);

flang/test/Evaluate/rewrite06.f90

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
2+
subroutine test_storage_size(n)
3+
interface
4+
function return_char(l)
5+
integer :: l
6+
character(l) :: return_char
7+
end function
8+
end interface
9+
integer n
10+
!CHECK: PRINT *, storage_size(return_char(n))
11+
print*, storage_size(return_char(n))
12+
!CHECK: PRINT *, sizeof(return_char(n))
13+
print*, sizeof(return_char(n))
14+
end subroutine
15+
16+
module pdts
17+
type t(l)
18+
integer, len :: l
19+
character(l) :: c
20+
end type
21+
contains
22+
function return_pdt(n)
23+
type(t(n)) :: return_pdt
24+
end function
25+
subroutine test(k)
26+
! NOTE: flang design for length parametrized derived type
27+
! is to use allocatables for the automatic components. Hence,
28+
! their size is independent from the length parameters and is
29+
! a compile time constant.
30+
!CHECK: PRINT *, 192_4
31+
print *, storage_size(return_pdt(k))
32+
end subroutine
33+
end module
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
! Test storage_size with characters
2+
! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
3+
4+
! check-label: func.func @_QPtest_storage_size
5+
subroutine test_storage_size(n)
6+
interface
7+
function return_char(l)
8+
integer :: l
9+
character(l) :: return_char
10+
end function
11+
end interface
12+
integer n
13+
print*, storage_size(return_char(n))
14+
! CHECK: %[[val_16:.*]] = fir.call @_QPreturn_char(%[[res_addr:[^,]*]], %[[res_len:[^,]*]], {{.*}})
15+
! CHECK: %[[res:.*]]:2 = hlfir.declare %[[res_addr]] typeparams %[[res_len]]
16+
! CHECK: %[[val_18:.*]] = fir.embox %[[res]]#1 typeparams %[[res_len]] : (!fir.ref<!fir.char<1,?>>, index) -> !fir.box<!fir.char<1,?>>
17+
! CHECK: %[[val_19:.*]] = fir.box_elesize %[[val_18]] : (!fir.box<!fir.char<1,?>>) -> i32
18+
! CHECK: %[[val_20:.*]] = arith.constant 8 : i32
19+
! CHECK: %[[val_21:.*]] = arith.muli %[[val_19]], %[[val_20]] : i32
20+
! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[val_21]])
21+
end subroutine
22+
23+
function return_char(l)
24+
integer :: l
25+
character(l) :: return_char
26+
end function
27+
28+
call test_storage_size(42)
29+
print *, 42*8
30+
end

flang/test/Semantics/call05.f90

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,15 @@ subroutine smb(b)
155155
integer, allocatable, intent(in) :: b(:)
156156
end
157157

158+
function return_deferred_length_ptr()
159+
character(len=:), pointer :: return_deferred_length_ptr
160+
end function
161+
162+
function return_explicit_length_ptr(n)
163+
integer :: n
164+
character(len=n), pointer :: return_explicit_length_ptr
165+
end function
166+
158167
subroutine test()
159168

160169
!ERROR: Dummy and actual arguments must defer the same type parameters when POINTER or ALLOCATABLE
@@ -167,6 +176,16 @@ subroutine test()
167176

168177
call smp2(p1) ! ok
169178

179+
call smp(return_deferred_length_ptr()) ! ok
180+
181+
!ERROR: Dummy and actual arguments must defer the same type parameters when POINTER or ALLOCATABLE
182+
call smp2(return_deferred_length_ptr())
183+
184+
!ERROR: Dummy and actual arguments must defer the same type parameters when POINTER or ALLOCATABLE
185+
call smp(return_explicit_length_ptr(10))
186+
187+
call smp2(return_explicit_length_ptr(10)) ! ok
188+
170189
!ERROR: ALLOCATABLE dummy argument 'a=' must be associated with an ALLOCATABLE actual argument
171190
call sma(t2(:))
172191

0 commit comments

Comments
 (0)