diff --git a/flang/include/flang/Lower/Allocatable.h b/flang/include/flang/Lower/Allocatable.h index 1209b157ed1f41..0e89af94af40f6 100644 --- a/flang/include/flang/Lower/Allocatable.h +++ b/flang/include/flang/Lower/Allocatable.h @@ -15,7 +15,7 @@ #include "flang/Lower/AbstractConverter.h" #include "flang/Optimizer/Builder/MutableBox.h" -#include "flang/Runtime/allocator-registry.h" +#include "flang/Runtime/allocator-registry-consts.h" #include "llvm/ADT/StringRef.h" namespace mlir { diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h index e7955c2fc0314d..bc0020e614db24 100644 --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -16,7 +16,7 @@ #include "flang/Optimizer/Builder/Runtime/Numeric.h" #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" #include "flang/Runtime/entry-names.h" -#include "flang/Runtime/iostat.h" +#include "flang/Runtime/iostat-consts.h" #include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" diff --git a/flang/include/flang/Optimizer/Builder/MutableBox.h b/flang/include/flang/Optimizer/Builder/MutableBox.h index fea7c7204837b4..39657ddaf6e03a 100644 --- a/flang/include/flang/Optimizer/Builder/MutableBox.h +++ b/flang/include/flang/Optimizer/Builder/MutableBox.h @@ -14,7 +14,7 @@ #define FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H #include "flang/Optimizer/Builder/BoxValue.h" -#include "flang/Runtime/allocator-registry.h" +#include "flang/Runtime/allocator-registry-consts.h" #include "llvm/ADT/StringRef.h" namespace mlir { diff --git a/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h b/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h index ff0cf29e8073e6..9cccf8db87270e 100644 --- a/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h +++ b/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h @@ -23,7 +23,7 @@ #define OPTIMIZER_DESCRIPTOR_MODEL_H #include "flang/ISO_Fortran_binding_wrapper.h" -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/BuiltinTypes.h" #include "llvm/Support/ErrorHandling.h" diff --git a/flang/include/flang/Runtime/CUDA/allocatable.h b/flang/include/flang/Runtime/CUDA/allocatable.h index e2156281d1b2b0..0a96f73b6be44b 100644 --- a/flang/include/flang/Runtime/CUDA/allocatable.h +++ b/flang/include/flang/Runtime/CUDA/allocatable.h @@ -9,7 +9,7 @@ #ifndef FORTRAN_RUNTIME_CUDA_ALLOCATABLE_H_ #define FORTRAN_RUNTIME_CUDA_ALLOCATABLE_H_ -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Runtime/entry-names.h" namespace Fortran::runtime::cuda { diff --git a/flang/include/flang/Runtime/CUDA/allocator.h b/flang/include/flang/Runtime/CUDA/allocator.h index 618da44c675d85..b6f0e7f303176c 100644 --- a/flang/include/flang/Runtime/CUDA/allocator.h +++ b/flang/include/flang/Runtime/CUDA/allocator.h @@ -10,7 +10,7 @@ #define FORTRAN_RUNTIME_CUDA_ALLOCATOR_H_ #include "common.h" -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Runtime/entry-names.h" namespace Fortran::runtime::cuda { diff --git a/flang/include/flang/Runtime/CUDA/common.h b/flang/include/flang/Runtime/CUDA/common.h index 8172ea39a14f84..9c95f727ee6734 100644 --- a/flang/include/flang/Runtime/CUDA/common.h +++ b/flang/include/flang/Runtime/CUDA/common.h @@ -9,7 +9,7 @@ #ifndef FORTRAN_RUNTIME_CUDA_COMMON_H_ #define FORTRAN_RUNTIME_CUDA_COMMON_H_ -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Runtime/entry-names.h" /// Type of memory for allocation/deallocation diff --git a/flang/include/flang/Runtime/CUDA/descriptor.h b/flang/include/flang/Runtime/CUDA/descriptor.h index 93791012fdcc73..4c6c2c4694fd43 100644 --- a/flang/include/flang/Runtime/CUDA/descriptor.h +++ b/flang/include/flang/Runtime/CUDA/descriptor.h @@ -9,7 +9,7 @@ #ifndef FORTRAN_RUNTIME_CUDA_DESCRIPTOR_H_ #define FORTRAN_RUNTIME_CUDA_DESCRIPTOR_H_ -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Runtime/entry-names.h" #include diff --git a/flang/include/flang/Runtime/CUDA/memory.h b/flang/include/flang/Runtime/CUDA/memory.h index 2bb083b0dd75cb..fbe4941260ff92 100644 --- a/flang/include/flang/Runtime/CUDA/memory.h +++ b/flang/include/flang/Runtime/CUDA/memory.h @@ -9,7 +9,7 @@ #ifndef FORTRAN_RUNTIME_CUDA_MEMORY_H_ #define FORTRAN_RUNTIME_CUDA_MEMORY_H_ -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Runtime/entry-names.h" #include diff --git a/flang/include/flang/Runtime/allocator-registry-consts.h b/flang/include/flang/Runtime/allocator-registry-consts.h new file mode 100644 index 00000000000000..70735c2fc7a71c --- /dev/null +++ b/flang/include/flang/Runtime/allocator-registry-consts.h @@ -0,0 +1,20 @@ +//===-- include/flang/Runtime/allocator-registry-consts.h -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_CONSTS_H_ +#define FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_CONSTS_H_ + +static constexpr unsigned kDefaultAllocator = 0; + +// Allocator used for CUF +static constexpr unsigned kPinnedAllocatorPos = 1; +static constexpr unsigned kDeviceAllocatorPos = 2; +static constexpr unsigned kManagedAllocatorPos = 3; +static constexpr unsigned kUnifiedAllocatorPos = 4; + +#endif /* FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_CONSTS_H_ */ diff --git a/flang/include/flang/Runtime/allocator-registry.h b/flang/include/flang/Runtime/allocator-registry.h index 771fa8a9a9933c..4c3295edf13d9a 100644 --- a/flang/include/flang/Runtime/allocator-registry.h +++ b/flang/include/flang/Runtime/allocator-registry.h @@ -10,18 +10,11 @@ #define FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_H_ #include "flang/Common/api-attrs.h" +#include "flang/Runtime/allocator-registry-consts.h" #include #include #include -static constexpr unsigned kDefaultAllocator = 0; - -// Allocator used for CUF -static constexpr unsigned kPinnedAllocatorPos = 1; -static constexpr unsigned kDeviceAllocatorPos = 2; -static constexpr unsigned kManagedAllocatorPos = 3; -static constexpr unsigned kUnifiedAllocatorPos = 4; - #define MAX_ALLOCATOR 7 // 3 bits are reserved in the descriptor. namespace Fortran::runtime { diff --git a/flang/include/flang/Runtime/array-constructor-consts.h b/flang/include/flang/Runtime/array-constructor-consts.h new file mode 100644 index 00000000000000..ad3583eef29aad --- /dev/null +++ b/flang/include/flang/Runtime/array-constructor-consts.h @@ -0,0 +1,97 @@ +//===-- include/flang/Runtime/array-constructor-consts.h --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_ARRAY_CONSTRUCTOR_CONSTS_H_ +#define FORTRAN_RUNTIME_ARRAY_CONSTRUCTOR_CONSTS_H_ + +#include "flang/Runtime/descriptor-consts.h" +#include "flang/Runtime/entry-names.h" +#include + +namespace Fortran::runtime { +struct ArrayConstructorVector; + +// Max sizeof(ArrayConstructorVector) and sizeof(ArrayConstructorVector) for any +// target. +// TODO: Use target-specific size/alignment instead of overapproximation. +constexpr std::size_t MaxArrayConstructorVectorSizeInBytes = 2 * 40; +constexpr std::size_t MaxArrayConstructorVectorAlignInBytes = 8; + +// This file defines an API to "push" an evaluated array constructor value +// "from" into some storage "to" of an array constructor. It can be seen as a +// form of std::vector::push_back() implementation for Fortran array +// constructors. In the APIs and ArrayConstructorVector struct above: +// +// - "to" is a ranked-1 descriptor whose declared type is already set to the +// array constructor derived type. It may be already allocated, even before the +// first call to this API, or it may be unallocated. "to" extent is increased +// every time a "from" is pushed past its current extent. At this end of the +// API calls, its extent is the extent of the array constructor. If "to" is +// unallocated and its extent is not null, it is assumed this is the final array +// constructor extent value, and the first allocation already "reserves" storage +// space accordingly to avoid reallocations. +// - "from" is a scalar or array descriptor for the evaluated array +// constructor value that must be copied into the storage of "to" at +// "nextValuePosition". +// - "useValueLengthParameters" must be set to true if the array constructor +// has length parameters and no type spec. If it is true and "to" is +// unallocated, "to" will take the length parameters of "from". If it is true +// and "to" is an allocated character array constructor, it will be checked +// that "from" length matches the one from "to". When it is false, the +// character length must already be set in "to" before the first call to this +// API and "from" character lengths are allowed to mismatch from "to". +// - "nextValuePosition" is the zero based sequence position of "from" in the +// array constructor. It is updated after this call by the number of "from" +// elements. It should be set to zero by the caller of this API before the first +// call. +// - "actualAllocationSize" is the current allocation size of "to" storage. It +// may be bigger than "to" extent for reallocation optimization purposes, but +// should never be smaller, unless this is the first call and "to" is +// unallocated. It is updated by the runtime after each successful allocation or +// reallocation. It should be set to "to" extent if "to" is allocated before the +// first call of this API, and can be left undefined otherwise. +// +// Note that this API can be used with "to" being a variable (that can be +// discontiguous). This can be done when the variable is the left hand side of +// an assignment from an array constructor as long as: +// - none of the ac-value overlaps with the variable, +// - this is an intrinsic assignment that is not a whole allocatable +// assignment, *and* for a type that has no components requiring user defined +// assignments, +// - the variable is properly finalized before using this API if its need to, +// - "useValueLengthParameters" should be set to false in this case, even if +// the array constructor has no type-spec, since the variable may have a +// different character length than the array constructor values. + +extern "C" { +// API to initialize an ArrayConstructorVector before any values are pushed to +// it. Inlined code is only expected to allocate the "ArrayConstructorVector" +// class instance storage with sufficient size +// (MaxArrayConstructorVectorSizeInBytes is expected to be large enough for all +// supported targets). This avoids the need for the runtime to maintain a state, +// or to use dynamic allocation for it. +void RTDECL(InitArrayConstructorVector)(ArrayConstructorVector &vector, + Descriptor &to, bool useValueLengthParameters, + const char *sourceFile = nullptr, int sourceLine = 0); + +// Generic API to push any kind of entity into the array constructor (any +// Fortran type and any rank). +void RTDECL(PushArrayConstructorValue)( + ArrayConstructorVector &vector, const Descriptor &from); + +// API to push scalar array constructor value of: +// - a numerical or logical type, +// - or a derived type that has no length parameters, and no allocatable +// component (that would require deep copies). +// It requires no descriptor for the value that is passed via its base address. +void RTDECL(PushArrayConstructorSimpleScalar)( + ArrayConstructorVector &vector, void *from); +} // extern "C" +} // namespace Fortran::runtime + +#endif /* FORTRAN_RUNTIME_ARRAY_CONSTRUCTOR_CONSTS_H_ */ diff --git a/flang/include/flang/Runtime/array-constructor.h b/flang/include/flang/Runtime/array-constructor.h index 46fc0418c7991e..2f6aaae17c6508 100644 --- a/flang/include/flang/Runtime/array-constructor.h +++ b/flang/include/flang/Runtime/array-constructor.h @@ -12,6 +12,7 @@ #ifndef FORTRAN_RUNTIME_ARRAYCONSTRUCTOR_H_ #define FORTRAN_RUNTIME_ARRAYCONSTRUCTOR_H_ +#include "flang/Runtime/array-constructor-consts.h" #include "flang/Runtime/descriptor.h" #include "flang/Runtime/entry-names.h" #include @@ -43,76 +44,14 @@ struct ArrayConstructorVector { unsigned char useValueLengthParameters_ : 1; }; -// This file defines an API to "push" an evaluated array constructor value -// "from" into some storage "to" of an array constructor. It can be seen as a -// form of std::vector::push_back() implementation for Fortran array -// constructors. In the APIs and ArrayConstructorVector struct above: -// -// - "to" is a ranked-1 descriptor whose declared type is already set to the -// array constructor derived type. It may be already allocated, even before the -// first call to this API, or it may be unallocated. "to" extent is increased -// every time a "from" is pushed past its current extent. At this end of the -// API calls, its extent is the extent of the array constructor. If "to" is -// unallocated and its extent is not null, it is assumed this is the final array -// constructor extent value, and the first allocation already "reserves" storage -// space accordingly to avoid reallocations. -// - "from" is a scalar or array descriptor for the evaluated array -// constructor value that must be copied into the storage of "to" at -// "nextValuePosition". -// - "useValueLengthParameters" must be set to true if the array constructor -// has length parameters and no type spec. If it is true and "to" is -// unallocated, "to" will take the length parameters of "from". If it is true -// and "to" is an allocated character array constructor, it will be checked -// that "from" length matches the one from "to". When it is false, the -// character length must already be set in "to" before the first call to this -// API and "from" character lengths are allowed to mismatch from "to". -// - "nextValuePosition" is the zero based sequence position of "from" in the -// array constructor. It is updated after this call by the number of "from" -// elements. It should be set to zero by the caller of this API before the first -// call. -// - "actualAllocationSize" is the current allocation size of "to" storage. It -// may be bigger than "to" extent for reallocation optimization purposes, but -// should never be smaller, unless this is the first call and "to" is -// unallocated. It is updated by the runtime after each successful allocation or -// reallocation. It should be set to "to" extent if "to" is allocated before the -// first call of this API, and can be left undefined otherwise. -// -// Note that this API can be used with "to" being a variable (that can be -// discontiguous). This can be done when the variable is the left hand side of -// an assignment from an array constructor as long as: -// - none of the ac-value overlaps with the variable, -// - this is an intrinsic assignment that is not a whole allocatable -// assignment, *and* for a type that has no components requiring user defined -// assignments, -// - the variable is properly finalized before using this API if its need to, -// - "useValueLengthParameters" should be set to false in this case, even if -// the array constructor has no type-spec, since the variable may have a -// different character length than the array constructor values. - -extern "C" { -// API to initialize an ArrayConstructorVector before any values are pushed to -// it. Inlined code is only expected to allocate the "ArrayConstructorVector" -// class instance storage with sufficient size (using -// "2*sizeof(ArrayConstructorVector)" on the host should be safe regardless of -// the target the runtime is compiled for). This avoids the need for the runtime -// to maintain a state, or to use dynamic allocation for it. "vectorClassSize" -// is used to validate that lowering allocated enough space for it. -void RTDECL(InitArrayConstructorVector)(ArrayConstructorVector &vector, - Descriptor &to, bool useValueLengthParameters, int vectorClassSize, - const char *sourceFile = nullptr, int sourceLine = 0); - -// Generic API to push any kind of entity into the array constructor (any -// Fortran type and any rank). -void RTDECL(PushArrayConstructorValue)( - ArrayConstructorVector &vector, const Descriptor &from); +static_assert(sizeof(Fortran::runtime::ArrayConstructorVector) <= + MaxArrayConstructorVectorSizeInBytes, + "ABI requires sizeof(ArrayConstructorVector) to be smaller than " + "MaxArrayConstructorVectorSizeInBytes"); +static_assert(alignof(Fortran::runtime::ArrayConstructorVector) <= + MaxArrayConstructorVectorAlignInBytes, + "ABI requires alignof(ArrayConstructorVector) to be smaller than " + "MaxArrayConstructorVectorAlignInBytes"); -// API to push scalar array constructor value of: -// - a numerical or logical type, -// - or a derived type that has no length parameters, and no allocatable -// component (that would require deep copies). -// It requires no descriptor for the value that is passed via its base address. -void RTDECL(PushArrayConstructorSimpleScalar)( - ArrayConstructorVector &vector, void *from); -} // extern "C" } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_ARRAYCONSTRUCTOR_H_ diff --git a/flang/include/flang/Runtime/descriptor-consts.h b/flang/include/flang/Runtime/descriptor-consts.h new file mode 100644 index 00000000000000..3b2537579d5864 --- /dev/null +++ b/flang/include/flang/Runtime/descriptor-consts.h @@ -0,0 +1,74 @@ +//===-- include/flang/Runtime/descriptor-consts.h ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_DESCRIPTOR_CONSTS_H_ +#define FORTRAN_RUNTIME_DESCRIPTOR_CONSTS_H_ + +#include "flang/Common/api-attrs.h" +#include "flang/ISO_Fortran_binding_wrapper.h" +#include +#include + +// Value of the addendum presence flag. +#define _CFI_ADDENDUM_FLAG 1 +// Number of bits needed to be shifted when manipulating the allocator index. +#define _CFI_ALLOCATOR_IDX_SHIFT 1 +// Allocator index mask. +#define _CFI_ALLOCATOR_IDX_MASK 0b00001110 + +namespace Fortran::runtime::typeInfo { +using TypeParameterValue = std::int64_t; +class DerivedType; +} // namespace Fortran::runtime::typeInfo + +namespace Fortran::runtime { +class Descriptor; +using SubscriptValue = ISO::CFI_index_t; + +/// Returns size in bytes of the descriptor (not the data) +/// This must be at least as large as the largest descriptor of any target +/// triple. +static constexpr RT_API_ATTRS std::size_t MaxDescriptorSizeInBytes( + int rank, bool addendum = false, int lengthTypeParameters = 0) { + // Layout: + // + // fortran::runtime::Descriptor { + // ISO::CFI_cdesc_t { + // void *base_addr; (pointer -> up to 8 bytes) + // size_t elem_len; (up to 8 bytes) + // int version; (up to 4 bytes) + // CFI_rank_t rank; (unsigned char -> 1 byte) + // CFI_type_t type; (signed char -> 1 byte) + // CFI_attribute_t attribute; (unsigned char -> 1 byte) + // unsigned char extra; (1 byte) + // } + // } + // fortran::runtime::Dimension[rank] { + // ISO::CFI_dim_t { + // CFI_index_t lower_bound; (ptrdiff_t -> up to 8 bytes) + // CFI_index_t extent; (ptrdiff_t -> up to 8 bytes) + // CFI_index_t sm; (ptrdiff_t -> up to 8 bytes) + // } + // } + // fortran::runtime::DescriptorAddendum { + // const typeInfo::DerivedType *derivedType_; (pointer -> up to 8 + // bytes) typeInfo::TypeParameterValue len_[lenParameters]; (int64_t -> 8 + // bytes) + // } + std::size_t bytes{24u + rank * 24u}; + if (addendum || lengthTypeParameters > 0) { + if (lengthTypeParameters < 1) + lengthTypeParameters = 1; + bytes += 8u + static_cast(lengthTypeParameters) * 8u; + } + return bytes; +} + +} // namespace Fortran::runtime + +#endif /* FORTRAN_RUNTIME_DESCRIPTOR_CONSTS_H_ */ diff --git a/flang/include/flang/Runtime/descriptor.h b/flang/include/flang/Runtime/descriptor.h index e6300accfeac08..44e82c6a256873 100644 --- a/flang/include/flang/Runtime/descriptor.h +++ b/flang/include/flang/Runtime/descriptor.h @@ -19,6 +19,7 @@ // but should never reference this internal header. #include "flang/ISO_Fortran_binding_wrapper.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Runtime/memory.h" #include "flang/Runtime/type-code.h" #include @@ -28,14 +29,8 @@ #include #include -namespace Fortran::runtime::typeInfo { -using TypeParameterValue = std::int64_t; -class DerivedType; -} // namespace Fortran::runtime::typeInfo - namespace Fortran::runtime { -using SubscriptValue = ISO::CFI_index_t; class Terminator; RT_VAR_GROUP_BEGIN @@ -420,13 +415,6 @@ class Descriptor { void Dump(FILE * = stdout) const; -// Value of the addendum presence flag. -#define _CFI_ADDENDUM_FLAG 1 -// Number of bits needed to be shifted when manipulating the allocator index. -#define _CFI_ALLOCATOR_IDX_SHIFT 1 -// Allocator index mask. -#define _CFI_ALLOCATOR_IDX_MASK 0b00001110 - RT_API_ATTRS inline bool HasAddendum() const { return raw_.extra & _CFI_ADDENDUM_FLAG; } @@ -464,6 +452,8 @@ class alignas(Descriptor) StaticDescriptor { static constexpr bool hasAddendum{ADDENDUM || MAX_LEN_PARMS > 0}; static constexpr std::size_t byteSize{ Descriptor::SizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)}; + static_assert(byteSize <= + MaxDescriptorSizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)); RT_OFFLOAD_VAR_GROUP_END RT_API_ATTRS Descriptor &descriptor() { diff --git a/flang/include/flang/Runtime/io-api-consts.h b/flang/include/flang/Runtime/io-api-consts.h new file mode 100644 index 00000000000000..7ed8bf1489b3c2 --- /dev/null +++ b/flang/include/flang/Runtime/io-api-consts.h @@ -0,0 +1,368 @@ +//===-- include/flang/Runtime/io-api-consts.h -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_IO_API_CONSTS_H_ +#define FORTRAN_RUNTIME_IO_API_CONSTS_H_ + +#include "flang/Common/uint128.h" +#include "flang/Runtime/entry-names.h" +#include "flang/Runtime/iostat-consts.h" +#include "flang/Runtime/magic-numbers.h" +#include +#include + +namespace Fortran::runtime { +class Descriptor; +} // namespace Fortran::runtime + +namespace Fortran::runtime::io { + +struct NonTbpDefinedIoTable; +class NamelistGroup; +class IoStatementState; +using Cookie = IoStatementState *; +using ExternalUnit = int; +using AsynchronousId = int; + +static constexpr ExternalUnit DefaultOutputUnit{FORTRAN_DEFAULT_OUTPUT_UNIT}; +static constexpr ExternalUnit DefaultInputUnit{FORTRAN_DEFAULT_INPUT_UNIT}; + +// INQUIRE specifiers are encoded as simple base-26 packings of +// the spellings of their keywords. +using InquiryKeywordHash = std::uint64_t; +constexpr InquiryKeywordHash HashInquiryKeyword(const char *p) { + InquiryKeywordHash hash{1}; + while (char ch{*p++}) { + std::uint64_t letter{0}; + if (ch >= 'a' && ch <= 'z') { + letter = ch - 'a'; + } else { + letter = ch - 'A'; + } + hash = 26 * hash + letter; + } + return hash; +} + +extern "C" { + +#define IONAME(name) RTNAME(io##name) + +#ifndef IODECL +#define IODECL(name) RT_API_ATTRS IONAME(name) +#endif + +#ifndef IODEF +#define IODEF(name) RT_API_ATTRS IONAME(name) +#endif + +// These functions initiate data transfer statements (READ, WRITE, PRINT). +// Example: PRINT *, 666 is implemented as the series of calls: +// Cookie cookie{BeginExternalListOutput(DefaultOutputUnit, +// __FILE__, __LINE__)}; +// OutputInteger32(cookie, 666); +// EndIoStatement(cookie); +// Formatted I/O with explicit formats can supply the format as a +// const char * pointer with a length, or with a descriptor. + +// Internal I/O initiation +// Internal I/O can loan the runtime library an optional block of memory +// in which the library can maintain state across the calls that implement +// the internal transfer; use of these blocks can reduce the need for dynamic +// memory allocation &/or thread-local storage. The block must be sufficiently +// aligned to hold a pointer. +constexpr std::size_t RecommendedInternalIoScratchAreaBytes( + int maxFormatParenthesesNestingDepth) { + return 32 + 8 * maxFormatParenthesesNestingDepth; +} + +// For NAMELIST I/O, use the API for the appropriate form of list-directed +// I/O initiation and configuration, then call OutputNamelist/InputNamelist +// below. + +// Internal I/O to/from character arrays &/or non-default-kind character +// requires a descriptor, which is copied. +Cookie IODECL(BeginInternalArrayListOutput)(const Descriptor &, + void **scratchArea = nullptr, std::size_t scratchBytes = 0, + const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginInternalArrayListInput)(const Descriptor &, + void **scratchArea = nullptr, std::size_t scratchBytes = 0, + const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginInternalArrayFormattedOutput)(const Descriptor &, + const char *format, std::size_t formatLength, + const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, + std::size_t scratchBytes = 0, const char *sourceFile = nullptr, + int sourceLine = 0); +Cookie IODECL(BeginInternalArrayFormattedInput)(const Descriptor &, + const char *format, std::size_t formatLength, + const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, + std::size_t scratchBytes = 0, const char *sourceFile = nullptr, + int sourceLine = 0); + +// Internal I/O to/from a default-kind character scalar can avoid a +// descriptor. +Cookie IODECL(BeginInternalListOutput)(char *internal, + std::size_t internalLength, void **scratchArea = nullptr, + std::size_t scratchBytes = 0, const char *sourceFile = nullptr, + int sourceLine = 0); +Cookie IODECL(BeginInternalListInput)(const char *internal, + std::size_t internalLength, void **scratchArea = nullptr, + std::size_t scratchBytes = 0, const char *sourceFile = nullptr, + int sourceLine = 0); +Cookie IODECL(BeginInternalFormattedOutput)(char *internal, + std::size_t internalLength, const char *format, std::size_t formatLength, + const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, + std::size_t scratchBytes = 0, const char *sourceFile = nullptr, + int sourceLine = 0); +Cookie IODECL(BeginInternalFormattedInput)(const char *internal, + std::size_t internalLength, const char *format, std::size_t formatLength, + const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, + std::size_t scratchBytes = 0, const char *sourceFile = nullptr, + int sourceLine = 0); + +// External unit numbers must fit in default integers. When the integer +// provided as UNIT is of a wider type than the default integer, it could +// overflow when converted to a default integer. +// CheckUnitNumberInRange should be called to verify that a unit number of a +// wide integer type can fit in a default integer. Since it should be called +// before the BeginXXX(unit, ...) call, it has its own error handling interface. +// If handleError is false, and the unit number is out of range, the program +// will be terminated. Otherwise, if unit is out of range, a nonzero Iostat +// code is returned and ioMsg is set if it is not a nullptr. +enum Iostat IODECL(CheckUnitNumberInRange64)(std::int64_t unit, + bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0, + const char *sourceFile = nullptr, int sourceLine = 0); +enum Iostat IODECL(CheckUnitNumberInRange128)(common::int128_t unit, + bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0, + const char *sourceFile = nullptr, int sourceLine = 0); + +// External synchronous I/O initiation +Cookie IODECL(BeginExternalListOutput)(ExternalUnit = DefaultOutputUnit, + const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginExternalListInput)(ExternalUnit = DefaultInputUnit, + const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginExternalFormattedOutput)(const char *format, std::size_t, + const Descriptor *formatDescriptor = nullptr, + ExternalUnit = DefaultOutputUnit, const char *sourceFile = nullptr, + int sourceLine = 0); +Cookie IODECL(BeginExternalFormattedInput)(const char *format, std::size_t, + const Descriptor *formatDescriptor = nullptr, + ExternalUnit = DefaultInputUnit, const char *sourceFile = nullptr, + int sourceLine = 0); +Cookie IODECL(BeginUnformattedOutput)(ExternalUnit = DefaultOutputUnit, + const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginUnformattedInput)(ExternalUnit = DefaultInputUnit, + const char *sourceFile = nullptr, int sourceLine = 0); + +// WAIT(ID=) +Cookie IODECL(BeginWait)(ExternalUnit, AsynchronousId, + const char *sourceFile = nullptr, int sourceLine = 0); +// WAIT(no ID=) +Cookie IODECL(BeginWaitAll)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); + +// Other I/O statements +Cookie IODECL(BeginClose)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginFlush)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginBackspace)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginEndfile)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginRewind)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); + +// OPEN(UNIT=) and OPEN(NEWUNIT=) have distinct interfaces. +Cookie IODECL(BeginOpenUnit)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginOpenNewUnit)( + const char *sourceFile = nullptr, int sourceLine = 0); + +// The variant forms of INQUIRE() statements have distinct interfaces. +// BeginInquireIoLength() is basically a no-op output statement. +Cookie IODECL(BeginInquireUnit)( + ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginInquireFile)(const char *, std::size_t, + const char *sourceFile = nullptr, int sourceLine = 0); +Cookie IODECL(BeginInquireIoLength)( + const char *sourceFile = nullptr, int sourceLine = 0); + +// If an I/O statement has any IOSTAT=, ERR=, END=, or EOR= specifiers, +// call EnableHandlers() immediately after the Begin...() call. +// An output or OPEN statement may not enable HasEnd or HasEor. +// This call makes the runtime library defer those particular error/end +// conditions to the EndIoStatement() call rather than terminating +// the image. E.g., for READ(*,*,END=666) A, B, (C(J),J=1,N) +// Cookie cookie{BeginExternalListInput(DefaultInputUnit,__FILE__,__LINE__)}; +// EnableHandlers(cookie, false, false, true /*END=*/, false); +// if (InputReal64(cookie, &A)) { +// if (InputReal64(cookie, &B)) { +// for (int J{1}; J<=N; ++J) { +// if (!InputReal64(cookie, &C[J])) break; +// } +// } +// } +// if (EndIoStatement(cookie) == FORTRAN_RUTIME_IOSTAT_END) goto label666; +void IODECL(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false, + bool hasEnd = false, bool hasEor = false, bool hasIoMsg = false); + +// ASYNCHRONOUS='YES' or 'NO' on READ/WRITE/OPEN +// Use GetAsynchronousId() to handle ID=. +bool IODECL(SetAsynchronous)(Cookie, const char *, std::size_t); + +// Control list options. These return false on a error that the +// Begin...() call has specified will be handled by the caller. +// The interfaces that pass a default-kind CHARACTER argument +// are limited to passing specific case-insensitive keyword values. +// ADVANCE=YES, NO +bool IODECL(SetAdvance)(Cookie, const char *, std::size_t); +// BLANK=NULL, ZERO +bool IODECL(SetBlank)(Cookie, const char *, std::size_t); +// DECIMAL=COMMA, POINT +bool IODECL(SetDecimal)(Cookie, const char *, std::size_t); +// DELIM=APOSTROPHE, QUOTE, NONE +bool IODECL(SetDelim)(Cookie, const char *, std::size_t); +// PAD=YES, NO +bool IODECL(SetPad)(Cookie, const char *, std::size_t); +bool IODECL(SetPos)(Cookie, std::int64_t); +bool IODECL(SetRec)(Cookie, std::int64_t); +// ROUND=UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED +bool IODECL(SetRound)(Cookie, const char *, std::size_t); +// SIGN=PLUS, SUPPRESS, PROCESSOR_DEFINED +bool IODECL(SetSign)(Cookie, const char *, std::size_t); + +// Data item transfer for modes other than NAMELIST: +// Any data object that can be passed as an actual argument without the +// use of a temporary can be transferred by means of a descriptor; +// vector-valued subscripts and coindexing will require elementwise +// transfers &/or data copies. Unformatted transfers to/from contiguous +// blocks of local image memory can avoid the descriptor, and there +// are specializations for the most common scalar types. +// +// These functions return false when the I/O statement has encountered an +// error or end-of-file/record condition that the caller has indicated +// should not cause termination of the image by the runtime library. +// Once the statement has encountered an error, all following items will be +// ignored and also return false; but compiled code should check for errors +// and avoid the following items when they might crash. +bool IODECL(OutputDescriptor)(Cookie, const Descriptor &); +bool IODECL(InputDescriptor)(Cookie, const Descriptor &); +// Formatted (including list directed) I/O data items +bool IODECL(OutputInteger8)(Cookie, std::int8_t); +bool IODECL(OutputInteger16)(Cookie, std::int16_t); +bool IODECL(OutputInteger32)(Cookie, std::int32_t); +bool IODECL(OutputInteger64)(Cookie, std::int64_t); +bool IODECL(OutputInteger128)(Cookie, common::int128_t); +bool IODECL(InputInteger)(Cookie, std::int64_t &, int kind = 8); +bool IODECL(OutputReal32)(Cookie, float); +bool IODECL(InputReal32)(Cookie, float &); +bool IODECL(OutputReal64)(Cookie, double); +bool IODECL(InputReal64)(Cookie, double &); +bool IODECL(OutputComplex32)(Cookie, float, float); +bool IODECL(InputComplex32)(Cookie, float[2]); +bool IODECL(OutputComplex64)(Cookie, double, double); +bool IODECL(InputComplex64)(Cookie, double[2]); +bool IODECL(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1); +bool IODECL(OutputAscii)(Cookie, const char *, std::size_t); +bool IODECL(InputCharacter)(Cookie, char *, std::size_t, int kind = 1); +bool IODECL(InputAscii)(Cookie, char *, std::size_t); +bool IODECL(OutputLogical)(Cookie, bool); +bool IODECL(InputLogical)(Cookie, bool &); + +// NAMELIST I/O must be the only data item in an (otherwise) +// list-directed I/O statement. +bool IODECL(OutputNamelist)(Cookie, const NamelistGroup &); +bool IODECL(InputNamelist)(Cookie, const NamelistGroup &); + +// When an I/O list item has a derived type with a specific defined +// I/O subroutine of the appropriate generic kind for the active +// I/O data transfer statement (read/write, formatted/unformatted) +// that pertains to the type or its components, and those subroutines +// are dynamic or neither type-bound nor defined with interfaces +// in the same scope as the derived type (or an IMPORT statement has +// made such a generic interface inaccessible), these data item transfer +// APIs enable the I/O runtime to make the right calls to defined I/O +// subroutines. +bool IODECL(OutputDerivedType)( + Cookie, const Descriptor &, const NonTbpDefinedIoTable *); +bool IODECL(InputDerivedType)( + Cookie, const Descriptor &, const NonTbpDefinedIoTable *); + +// Additional specifier interfaces for the connection-list of +// on OPEN statement (only). SetBlank(), SetDecimal(), +// SetDelim(), GetIoMsg(), SetPad(), SetRound(), SetSign(), +// & SetAsynchronous() are also acceptable for OPEN. +// ACCESS=SEQUENTIAL, DIRECT, STREAM +bool IODECL(SetAccess)(Cookie, const char *, std::size_t); +// ACTION=READ, WRITE, or READWRITE +bool IODECL(SetAction)(Cookie, const char *, std::size_t); +// CARRIAGECONTROL=LIST, FORTRAN, NONE +bool IODECL(SetCarriagecontrol)(Cookie, const char *, std::size_t); +// CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP +bool IODECL(SetConvert)(Cookie, const char *, std::size_t); +// ENCODING=UTF-8, DEFAULT +bool IODECL(SetEncoding)(Cookie, const char *, std::size_t); +// FORM=FORMATTED, UNFORMATTED +bool IODECL(SetForm)(Cookie, const char *, std::size_t); +// POSITION=ASIS, REWIND, APPEND +bool IODECL(SetPosition)(Cookie, const char *, std::size_t); +bool IODECL(SetRecl)(Cookie, std::size_t); // RECL= + +// STATUS can be set during an OPEN or CLOSE statement. +// For OPEN: STATUS=OLD, NEW, SCRATCH, REPLACE, UNKNOWN +// For CLOSE: STATUS=KEEP, DELETE +bool IODECL(SetStatus)(Cookie, const char *, std::size_t); + +bool IODECL(SetFile)(Cookie, const char *, std::size_t chars); + +// Acquires the runtime-created unit number for OPEN(NEWUNIT=) +bool IODECL(GetNewUnit)(Cookie, int &, int kind = 4); + +// READ(SIZE=), after all input items +std::size_t IODECL(GetSize)(Cookie); + +// INQUIRE(IOLENGTH=), after all output items +std::size_t IODECL(GetIoLength)(Cookie); + +// GetIoMsg() does not modify its argument unless an error or +// end-of-record/file condition is present. +void IODECL(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG= + +// Defines ID= on READ/WRITE(ASYNCHRONOUS='YES') +AsynchronousId IODECL(GetAsynchronousId)(Cookie); + +// INQUIRE() specifiers are mostly identified by their NUL-terminated +// case-insensitive names. +// ACCESS, ACTION, ASYNCHRONOUS, BLANK, CONVERT, DECIMAL, DELIM, DIRECT, +// ENCODING, FORM, FORMATTED, NAME, PAD, POSITION, READ, READWRITE, ROUND, +// SEQUENTIAL, SIGN, STREAM, UNFORMATTED, WRITE: +bool IODECL(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t); +// EXIST, NAMED, OPENED, and PENDING (without ID): +bool IODECL(InquireLogical)(Cookie, InquiryKeywordHash, bool &); +// PENDING with ID +bool IODECL(InquirePendingId)(Cookie, AsynchronousId, bool &); +// NEXTREC, NUMBER, POS, RECL, SIZE +bool IODECL(InquireInteger64)( + Cookie, InquiryKeywordHash, std::int64_t &, int kind = 8); + +// This function must be called to end an I/O statement, and its +// cookie value may not be used afterwards unless it is recycled +// by the runtime library to serve a later I/O statement. +// The return value can be used to implement IOSTAT=, ERR=, END=, & EOR=; +// store it into the IOSTAT= variable if there is one, and test +// it to implement the various branches. The error condition +// returned is guaranteed to only be one of the problems that the +// EnableHandlers() call has indicated should be handled in compiled code +// rather than by terminating the image. +enum Iostat IODECL(EndIoStatement)(Cookie); + +} // extern "C" +} // namespace Fortran::runtime::io + +#endif /* FORTRAN_RUNTIME_IO_API_CONSTS_H_ */ diff --git a/flang/include/flang/Runtime/io-api.h b/flang/include/flang/Runtime/io-api.h index 328afc715a3f1e..b86c3cecb32c5a 100644 --- a/flang/include/flang/Runtime/io-api.h +++ b/flang/include/flang/Runtime/io-api.h @@ -13,7 +13,8 @@ #include "flang/Common/uint128.h" #include "flang/Runtime/entry-names.h" -#include "flang/Runtime/iostat.h" +#include "flang/Runtime/io-api-consts.h" +#include "flang/Runtime/iostat-consts.h" #include "flang/Runtime/magic-numbers.h" #include #include @@ -31,342 +32,8 @@ using Cookie = IoStatementState *; using ExternalUnit = int; using AsynchronousId = int; -static constexpr ExternalUnit DefaultOutputUnit{FORTRAN_DEFAULT_OUTPUT_UNIT}; -static constexpr ExternalUnit DefaultInputUnit{FORTRAN_DEFAULT_INPUT_UNIT}; - -// INQUIRE specifiers are encoded as simple base-26 packings of -// the spellings of their keywords. -using InquiryKeywordHash = std::uint64_t; -constexpr InquiryKeywordHash HashInquiryKeyword(const char *p) { - InquiryKeywordHash hash{1}; - while (char ch{*p++}) { - std::uint64_t letter{0}; - if (ch >= 'a' && ch <= 'z') { - letter = ch - 'a'; - } else { - letter = ch - 'A'; - } - hash = 26 * hash + letter; - } - return hash; -} - RT_API_ATTRS const char *InquiryKeywordHashDecode( char *buffer, std::size_t, InquiryKeywordHash); -extern "C" { - -#define IONAME(name) RTNAME(io##name) - -#ifndef IODECL -#define IODECL(name) RT_API_ATTRS IONAME(name) -#endif - -#ifndef IODEF -#define IODEF(name) RT_API_ATTRS IONAME(name) -#endif - -// These functions initiate data transfer statements (READ, WRITE, PRINT). -// Example: PRINT *, 666 is implemented as the series of calls: -// Cookie cookie{BeginExternalListOutput(DefaultOutputUnit, -// __FILE__, __LINE__)}; -// OutputInteger32(cookie, 666); -// EndIoStatement(cookie); -// Formatted I/O with explicit formats can supply the format as a -// const char * pointer with a length, or with a descriptor. - -// Internal I/O initiation -// Internal I/O can loan the runtime library an optional block of memory -// in which the library can maintain state across the calls that implement -// the internal transfer; use of these blocks can reduce the need for dynamic -// memory allocation &/or thread-local storage. The block must be sufficiently -// aligned to hold a pointer. -constexpr std::size_t RecommendedInternalIoScratchAreaBytes( - int maxFormatParenthesesNestingDepth) { - return 32 + 8 * maxFormatParenthesesNestingDepth; -} - -// For NAMELIST I/O, use the API for the appropriate form of list-directed -// I/O initiation and configuration, then call OutputNamelist/InputNamelist -// below. - -// Internal I/O to/from character arrays &/or non-default-kind character -// requires a descriptor, which is copied. -Cookie IODECL(BeginInternalArrayListOutput)(const Descriptor &, - void **scratchArea = nullptr, std::size_t scratchBytes = 0, - const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginInternalArrayListInput)(const Descriptor &, - void **scratchArea = nullptr, std::size_t scratchBytes = 0, - const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginInternalArrayFormattedOutput)(const Descriptor &, - const char *format, std::size_t formatLength, - const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, - std::size_t scratchBytes = 0, const char *sourceFile = nullptr, - int sourceLine = 0); -Cookie IODECL(BeginInternalArrayFormattedInput)(const Descriptor &, - const char *format, std::size_t formatLength, - const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, - std::size_t scratchBytes = 0, const char *sourceFile = nullptr, - int sourceLine = 0); - -// Internal I/O to/from a default-kind character scalar can avoid a -// descriptor. -Cookie IODECL(BeginInternalListOutput)(char *internal, - std::size_t internalLength, void **scratchArea = nullptr, - std::size_t scratchBytes = 0, const char *sourceFile = nullptr, - int sourceLine = 0); -Cookie IODECL(BeginInternalListInput)(const char *internal, - std::size_t internalLength, void **scratchArea = nullptr, - std::size_t scratchBytes = 0, const char *sourceFile = nullptr, - int sourceLine = 0); -Cookie IODECL(BeginInternalFormattedOutput)(char *internal, - std::size_t internalLength, const char *format, std::size_t formatLength, - const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, - std::size_t scratchBytes = 0, const char *sourceFile = nullptr, - int sourceLine = 0); -Cookie IODECL(BeginInternalFormattedInput)(const char *internal, - std::size_t internalLength, const char *format, std::size_t formatLength, - const Descriptor *formatDescriptor = nullptr, void **scratchArea = nullptr, - std::size_t scratchBytes = 0, const char *sourceFile = nullptr, - int sourceLine = 0); - -// External unit numbers must fit in default integers. When the integer -// provided as UNIT is of a wider type than the default integer, it could -// overflow when converted to a default integer. -// CheckUnitNumberInRange should be called to verify that a unit number of a -// wide integer type can fit in a default integer. Since it should be called -// before the BeginXXX(unit, ...) call, it has its own error handling interface. -// If handleError is false, and the unit number is out of range, the program -// will be terminated. Otherwise, if unit is out of range, a nonzero Iostat -// code is returned and ioMsg is set if it is not a nullptr. -enum Iostat IODECL(CheckUnitNumberInRange64)(std::int64_t unit, - bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0, - const char *sourceFile = nullptr, int sourceLine = 0); -enum Iostat IODECL(CheckUnitNumberInRange128)(common::int128_t unit, - bool handleError, char *ioMsg = nullptr, std::size_t ioMsgLength = 0, - const char *sourceFile = nullptr, int sourceLine = 0); - -// External synchronous I/O initiation -Cookie IODECL(BeginExternalListOutput)(ExternalUnit = DefaultOutputUnit, - const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginExternalListInput)(ExternalUnit = DefaultInputUnit, - const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginExternalFormattedOutput)(const char *format, std::size_t, - const Descriptor *formatDescriptor = nullptr, - ExternalUnit = DefaultOutputUnit, const char *sourceFile = nullptr, - int sourceLine = 0); -Cookie IODECL(BeginExternalFormattedInput)(const char *format, std::size_t, - const Descriptor *formatDescriptor = nullptr, - ExternalUnit = DefaultInputUnit, const char *sourceFile = nullptr, - int sourceLine = 0); -Cookie IODECL(BeginUnformattedOutput)(ExternalUnit = DefaultOutputUnit, - const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginUnformattedInput)(ExternalUnit = DefaultInputUnit, - const char *sourceFile = nullptr, int sourceLine = 0); - -// WAIT(ID=) -Cookie IODECL(BeginWait)(ExternalUnit, AsynchronousId, - const char *sourceFile = nullptr, int sourceLine = 0); -// WAIT(no ID=) -Cookie IODECL(BeginWaitAll)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); - -// Other I/O statements -Cookie IODECL(BeginClose)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginFlush)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginBackspace)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginEndfile)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginRewind)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); - -// OPEN(UNIT=) and OPEN(NEWUNIT=) have distinct interfaces. -Cookie IODECL(BeginOpenUnit)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginOpenNewUnit)( - const char *sourceFile = nullptr, int sourceLine = 0); - -// The variant forms of INQUIRE() statements have distinct interfaces. -// BeginInquireIoLength() is basically a no-op output statement. -Cookie IODECL(BeginInquireUnit)( - ExternalUnit, const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginInquireFile)(const char *, std::size_t, - const char *sourceFile = nullptr, int sourceLine = 0); -Cookie IODECL(BeginInquireIoLength)( - const char *sourceFile = nullptr, int sourceLine = 0); - -// If an I/O statement has any IOSTAT=, ERR=, END=, or EOR= specifiers, -// call EnableHandlers() immediately after the Begin...() call. -// An output or OPEN statement may not enable HasEnd or HasEor. -// This call makes the runtime library defer those particular error/end -// conditions to the EndIoStatement() call rather than terminating -// the image. E.g., for READ(*,*,END=666) A, B, (C(J),J=1,N) -// Cookie cookie{BeginExternalListInput(DefaultInputUnit,__FILE__,__LINE__)}; -// EnableHandlers(cookie, false, false, true /*END=*/, false); -// if (InputReal64(cookie, &A)) { -// if (InputReal64(cookie, &B)) { -// for (int J{1}; J<=N; ++J) { -// if (!InputReal64(cookie, &C[J])) break; -// } -// } -// } -// if (EndIoStatement(cookie) == FORTRAN_RUTIME_IOSTAT_END) goto label666; -void IODECL(EnableHandlers)(Cookie, bool hasIoStat = false, bool hasErr = false, - bool hasEnd = false, bool hasEor = false, bool hasIoMsg = false); - -// ASYNCHRONOUS='YES' or 'NO' on READ/WRITE/OPEN -// Use GetAsynchronousId() to handle ID=. -bool IODECL(SetAsynchronous)(Cookie, const char *, std::size_t); - -// Control list options. These return false on a error that the -// Begin...() call has specified will be handled by the caller. -// The interfaces that pass a default-kind CHARACTER argument -// are limited to passing specific case-insensitive keyword values. -// ADVANCE=YES, NO -bool IODECL(SetAdvance)(Cookie, const char *, std::size_t); -// BLANK=NULL, ZERO -bool IODECL(SetBlank)(Cookie, const char *, std::size_t); -// DECIMAL=COMMA, POINT -bool IODECL(SetDecimal)(Cookie, const char *, std::size_t); -// DELIM=APOSTROPHE, QUOTE, NONE -bool IODECL(SetDelim)(Cookie, const char *, std::size_t); -// PAD=YES, NO -bool IODECL(SetPad)(Cookie, const char *, std::size_t); -bool IODECL(SetPos)(Cookie, std::int64_t); -bool IODECL(SetRec)(Cookie, std::int64_t); -// ROUND=UP, DOWN, ZERO, NEAREST, COMPATIBLE, PROCESSOR_DEFINED -bool IODECL(SetRound)(Cookie, const char *, std::size_t); -// SIGN=PLUS, SUPPRESS, PROCESSOR_DEFINED -bool IODECL(SetSign)(Cookie, const char *, std::size_t); - -// Data item transfer for modes other than NAMELIST: -// Any data object that can be passed as an actual argument without the -// use of a temporary can be transferred by means of a descriptor; -// vector-valued subscripts and coindexing will require elementwise -// transfers &/or data copies. Unformatted transfers to/from contiguous -// blocks of local image memory can avoid the descriptor, and there -// are specializations for the most common scalar types. -// -// These functions return false when the I/O statement has encountered an -// error or end-of-file/record condition that the caller has indicated -// should not cause termination of the image by the runtime library. -// Once the statement has encountered an error, all following items will be -// ignored and also return false; but compiled code should check for errors -// and avoid the following items when they might crash. -bool IODECL(OutputDescriptor)(Cookie, const Descriptor &); -bool IODECL(InputDescriptor)(Cookie, const Descriptor &); -// Formatted (including list directed) I/O data items -bool IODECL(OutputInteger8)(Cookie, std::int8_t); -bool IODECL(OutputInteger16)(Cookie, std::int16_t); -bool IODECL(OutputInteger32)(Cookie, std::int32_t); -bool IODECL(OutputInteger64)(Cookie, std::int64_t); -bool IODECL(OutputInteger128)(Cookie, common::int128_t); -bool IODECL(InputInteger)(Cookie, std::int64_t &, int kind = 8); -bool IODECL(OutputReal32)(Cookie, float); -bool IODECL(InputReal32)(Cookie, float &); -bool IODECL(OutputReal64)(Cookie, double); -bool IODECL(InputReal64)(Cookie, double &); -bool IODECL(OutputComplex32)(Cookie, float, float); -bool IODECL(InputComplex32)(Cookie, float[2]); -bool IODECL(OutputComplex64)(Cookie, double, double); -bool IODECL(InputComplex64)(Cookie, double[2]); -bool IODECL(OutputCharacter)(Cookie, const char *, std::size_t, int kind = 1); -bool IODECL(OutputAscii)(Cookie, const char *, std::size_t); -bool IODECL(InputCharacter)(Cookie, char *, std::size_t, int kind = 1); -bool IODECL(InputAscii)(Cookie, char *, std::size_t); -bool IODECL(OutputLogical)(Cookie, bool); -bool IODECL(InputLogical)(Cookie, bool &); - -// NAMELIST I/O must be the only data item in an (otherwise) -// list-directed I/O statement. -bool IODECL(OutputNamelist)(Cookie, const NamelistGroup &); -bool IODECL(InputNamelist)(Cookie, const NamelistGroup &); - -// When an I/O list item has a derived type with a specific defined -// I/O subroutine of the appropriate generic kind for the active -// I/O data transfer statement (read/write, formatted/unformatted) -// that pertains to the type or its components, and those subroutines -// are dynamic or neither type-bound nor defined with interfaces -// in the same scope as the derived type (or an IMPORT statement has -// made such a generic interface inaccessible), these data item transfer -// APIs enable the I/O runtime to make the right calls to defined I/O -// subroutines. -bool IODECL(OutputDerivedType)( - Cookie, const Descriptor &, const NonTbpDefinedIoTable *); -bool IODECL(InputDerivedType)( - Cookie, const Descriptor &, const NonTbpDefinedIoTable *); - -// Additional specifier interfaces for the connection-list of -// on OPEN statement (only). SetBlank(), SetDecimal(), -// SetDelim(), GetIoMsg(), SetPad(), SetRound(), SetSign(), -// & SetAsynchronous() are also acceptable for OPEN. -// ACCESS=SEQUENTIAL, DIRECT, STREAM -bool IODECL(SetAccess)(Cookie, const char *, std::size_t); -// ACTION=READ, WRITE, or READWRITE -bool IODECL(SetAction)(Cookie, const char *, std::size_t); -// CARRIAGECONTROL=LIST, FORTRAN, NONE -bool IODECL(SetCarriagecontrol)(Cookie, const char *, std::size_t); -// CONVERT=NATIVE, LITTLE_ENDIAN, BIG_ENDIAN, or SWAP -bool IODECL(SetConvert)(Cookie, const char *, std::size_t); -// ENCODING=UTF-8, DEFAULT -bool IODECL(SetEncoding)(Cookie, const char *, std::size_t); -// FORM=FORMATTED, UNFORMATTED -bool IODECL(SetForm)(Cookie, const char *, std::size_t); -// POSITION=ASIS, REWIND, APPEND -bool IODECL(SetPosition)(Cookie, const char *, std::size_t); -bool IODECL(SetRecl)(Cookie, std::size_t); // RECL= - -// STATUS can be set during an OPEN or CLOSE statement. -// For OPEN: STATUS=OLD, NEW, SCRATCH, REPLACE, UNKNOWN -// For CLOSE: STATUS=KEEP, DELETE -bool IODECL(SetStatus)(Cookie, const char *, std::size_t); - -bool IODECL(SetFile)(Cookie, const char *, std::size_t chars); - -// Acquires the runtime-created unit number for OPEN(NEWUNIT=) -bool IODECL(GetNewUnit)(Cookie, int &, int kind = 4); - -// READ(SIZE=), after all input items -std::size_t IODECL(GetSize)(Cookie); - -// INQUIRE(IOLENGTH=), after all output items -std::size_t IODECL(GetIoLength)(Cookie); - -// GetIoMsg() does not modify its argument unless an error or -// end-of-record/file condition is present. -void IODECL(GetIoMsg)(Cookie, char *, std::size_t); // IOMSG= - -// Defines ID= on READ/WRITE(ASYNCHRONOUS='YES') -AsynchronousId IODECL(GetAsynchronousId)(Cookie); - -// INQUIRE() specifiers are mostly identified by their NUL-terminated -// case-insensitive names. -// ACCESS, ACTION, ASYNCHRONOUS, BLANK, CONVERT, DECIMAL, DELIM, DIRECT, -// ENCODING, FORM, FORMATTED, NAME, PAD, POSITION, READ, READWRITE, ROUND, -// SEQUENTIAL, SIGN, STREAM, UNFORMATTED, WRITE: -bool IODECL(InquireCharacter)(Cookie, InquiryKeywordHash, char *, std::size_t); -// EXIST, NAMED, OPENED, and PENDING (without ID): -bool IODECL(InquireLogical)(Cookie, InquiryKeywordHash, bool &); -// PENDING with ID -bool IODECL(InquirePendingId)(Cookie, AsynchronousId, bool &); -// NEXTREC, NUMBER, POS, RECL, SIZE -bool IODECL(InquireInteger64)( - Cookie, InquiryKeywordHash, std::int64_t &, int kind = 8); - -// This function must be called to end an I/O statement, and its -// cookie value may not be used afterwards unless it is recycled -// by the runtime library to serve a later I/O statement. -// The return value can be used to implement IOSTAT=, ERR=, END=, & EOR=; -// store it into the IOSTAT= variable if there is one, and test -// it to implement the various branches. The error condition -// returned is guaranteed to only be one of the problems that the -// EnableHandlers() call has indicated should be handled in compiled code -// rather than by terminating the image. -enum Iostat IODECL(EndIoStatement)(Cookie); - -} // extern "C" } // namespace Fortran::runtime::io #endif diff --git a/flang/include/flang/Runtime/iostat-consts.h b/flang/include/flang/Runtime/iostat-consts.h new file mode 100644 index 00000000000000..26bf75f59fa0d6 --- /dev/null +++ b/flang/include/flang/Runtime/iostat-consts.h @@ -0,0 +1,93 @@ +//===-- include/flang/Runtime/iostat-consts.h -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_RUNTIME_IOSTAT_CONSTS_H_ +#define FORTRAN_RUNTIME_IOSTAT_CONSTS_H_ + +#include "flang/Common/api-attrs.h" +#include "flang/Runtime/magic-numbers.h" + +namespace Fortran::runtime::io { + +// The value of IOSTAT= is zero when no error, end-of-record, +// or end-of-file condition has arisen; errors are positive values. +// (See 12.11.5 in Fortran 2018 for the complete requirements; +// these constants must match the values of their corresponding +// named constants in the predefined module ISO_FORTRAN_ENV, so +// they're actually defined in another magic-numbers.h header file +// so that they can be included both here and there.) +enum Iostat { + IostatOk = 0, // no error, EOF, or EOR condition + + // These error codes are required by Fortran (see 12.10.2.16-17) to be + // negative integer values + IostatEnd = FORTRAN_RUNTIME_IOSTAT_END, // end-of-file on input & no error + // End-of-record on non-advancing input, no EOF or error + IostatEor = FORTRAN_RUNTIME_IOSTAT_EOR, + + // This value is also required to be negative (12.11.5 bullet 6). + // It signifies a FLUSH statement on an unflushable unit. + IostatUnflushable = FORTRAN_RUNTIME_IOSTAT_FLUSH, + + // Other errors are positive. We use "errno" values unchanged. + // This error is exported in ISO_Fortran_env. + IostatInquireInternalUnit = FORTRAN_RUNTIME_IOSTAT_INQUIRE_INTERNAL_UNIT, + + // The remaining error codes are not exported. + IostatGenericError = 1001, // see IOMSG= for details + IostatRecordWriteOverrun, + IostatRecordReadOverrun, + IostatInternalWriteOverrun, + IostatErrorInFormat, + IostatErrorInKeyword, + IostatEndfileDirect, + IostatEndfileUnwritable, + IostatOpenBadRecl, + IostatOpenUnknownSize, + IostatOpenBadAppend, + IostatWriteToReadOnly, + IostatReadFromWriteOnly, + IostatBackspaceNonSequential, + IostatBackspaceAtFirstRecord, + IostatRewindNonSequential, + IostatWriteAfterEndfile, + IostatFormattedIoOnUnformattedUnit, + IostatUnformattedIoOnFormattedUnit, + IostatListIoOnDirectAccessUnit, + IostatUnformattedChildOnFormattedParent, + IostatFormattedChildOnUnformattedParent, + IostatChildInputFromOutputParent, + IostatChildOutputToInputParent, + IostatShortRead, + IostatMissingTerminator, + IostatBadUnformattedRecord, + IostatUTF8Decoding, + IostatUnitOverflow, + IostatBadRealInput, + IostatBadScaleFactor, + IostatBadAsynchronous, + IostatBadWaitUnit, + IostatBOZInputOverflow, + IostatIntegerInputOverflow, + IostatRealInputOverflow, + IostatOpenAlreadyConnected, + IostatCannotReposition, + IostatBadWaitId, + IostatTooManyAsyncOps, + IostatBadBackspaceUnit, + IostatBadUnitNumber, + IostatBadFlushUnit, + IostatBadOpOnChildUnit, + IostatBadNewUnit, + IostatBadListDirectedInputSeparator, + IostatNonExternalDefinedUnformattedIo, +}; + +} // namespace Fortran::runtime::io + +#endif // FORTRAN_RUNTIME_IOSTAT_CONSTS_H_ diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h index 6ce7c82b424eb7..d8db68a3a1c2ee 100644 --- a/flang/include/flang/Runtime/iostat.h +++ b/flang/include/flang/Runtime/iostat.h @@ -11,83 +11,11 @@ #ifndef FORTRAN_RUNTIME_IOSTAT_H_ #define FORTRAN_RUNTIME_IOSTAT_H_ -#include "flang/Common/api-attrs.h" -#include "flang/Runtime/magic-numbers.h" -namespace Fortran::runtime::io { - -// The value of IOSTAT= is zero when no error, end-of-record, -// or end-of-file condition has arisen; errors are positive values. -// (See 12.11.5 in Fortran 2018 for the complete requirements; -// these constants must match the values of their corresponding -// named constants in the predefined module ISO_FORTRAN_ENV, so -// they're actually defined in another magic-numbers.h header file -// so that they can be included both here and there.) -enum Iostat { - IostatOk = 0, // no error, EOF, or EOR condition - - // These error codes are required by Fortran (see 12.10.2.16-17) to be - // negative integer values - IostatEnd = FORTRAN_RUNTIME_IOSTAT_END, // end-of-file on input & no error - // End-of-record on non-advancing input, no EOF or error - IostatEor = FORTRAN_RUNTIME_IOSTAT_EOR, - // This value is also required to be negative (12.11.5 bullet 6). - // It signifies a FLUSH statement on an unflushable unit. - IostatUnflushable = FORTRAN_RUNTIME_IOSTAT_FLUSH, - - // Other errors are positive. We use "errno" values unchanged. - // This error is exported in ISO_Fortran_env. - IostatInquireInternalUnit = FORTRAN_RUNTIME_IOSTAT_INQUIRE_INTERNAL_UNIT, +#include "flang/Common/api-attrs.h" +#include "flang/Runtime/iostat-consts.h" - // The remaining error codes are not exported. - IostatGenericError = 1001, // see IOMSG= for details - IostatRecordWriteOverrun, - IostatRecordReadOverrun, - IostatInternalWriteOverrun, - IostatErrorInFormat, - IostatErrorInKeyword, - IostatEndfileDirect, - IostatEndfileUnwritable, - IostatOpenBadRecl, - IostatOpenUnknownSize, - IostatOpenBadAppend, - IostatWriteToReadOnly, - IostatReadFromWriteOnly, - IostatBackspaceNonSequential, - IostatBackspaceAtFirstRecord, - IostatRewindNonSequential, - IostatWriteAfterEndfile, - IostatFormattedIoOnUnformattedUnit, - IostatUnformattedIoOnFormattedUnit, - IostatListIoOnDirectAccessUnit, - IostatUnformattedChildOnFormattedParent, - IostatFormattedChildOnUnformattedParent, - IostatChildInputFromOutputParent, - IostatChildOutputToInputParent, - IostatShortRead, - IostatMissingTerminator, - IostatBadUnformattedRecord, - IostatUTF8Decoding, - IostatUnitOverflow, - IostatBadRealInput, - IostatBadScaleFactor, - IostatBadAsynchronous, - IostatBadWaitUnit, - IostatBOZInputOverflow, - IostatIntegerInputOverflow, - IostatRealInputOverflow, - IostatOpenAlreadyConnected, - IostatCannotReposition, - IostatBadWaitId, - IostatTooManyAsyncOps, - IostatBadBackspaceUnit, - IostatBadUnitNumber, - IostatBadFlushUnit, - IostatBadOpOnChildUnit, - IostatBadNewUnit, - IostatBadListDirectedInputSeparator, - IostatNonExternalDefinedUnformattedIo, -}; +namespace Fortran::runtime::io { RT_API_ATTRS const char *IostatErrorString(int); diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 41b739560aea83..292b0783974369 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -56,7 +56,7 @@ #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Transforms/Passes.h" #include "flang/Parser/parse-tree.h" -#include "flang/Runtime/iostat.h" +#include "flang/Runtime/iostat-consts.h" #include "flang/Semantics/runtime-type-info.h" #include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 197e526973b4d3..ff122c21e37ade 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -39,7 +39,7 @@ #include "flang/Optimizer/Support/FatalError.h" #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Support/Utils.h" -#include "flang/Runtime/allocator-registry.h" +#include "flang/Runtime/allocator-registry-consts.h" #include "flang/Semantics/runtime-type-info.h" #include "flang/Semantics/tools.h" #include "llvm/Support/CommandLine.h" diff --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp index 1894b0cfd1bec2..6a918d844c12e4 100644 --- a/flang/lib/Lower/IO.cpp +++ b/flang/lib/Lower/IO.cpp @@ -33,7 +33,7 @@ #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/Support/FIRContext.h" #include "flang/Parser/parse-tree.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" #include "flang/Semantics/runtime-type-info.h" #include "flang/Semantics/tools.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp index 2758da48bceca4..547cebefd2df47 100644 --- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp @@ -41,7 +41,7 @@ #include "flang/Optimizer/Support/FatalError.h" #include "flang/Optimizer/Support/Utils.h" #include "flang/Runtime/entry-names.h" -#include "flang/Runtime/iostat.h" +#include "flang/Runtime/iostat-consts.h" #include "mlir/Dialect/Complex/IR/Complex.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/Dialect/Math/IR/Math.h" diff --git a/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp b/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp index c786bef5cb1c4c..0d56cd2edc99b5 100644 --- a/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp @@ -9,7 +9,7 @@ #include "flang/Optimizer/Builder/Runtime/ArrayConstructor.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" -#include "flang/Runtime/array-constructor.h" +#include "flang/Runtime/array-constructor-consts.h" using namespace Fortran::runtime; @@ -25,12 +25,13 @@ mlir::Value fir::runtime::genInitArrayConstructorVector( mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value toBox, mlir::Value useValueLengthParameters) { // Allocate storage for the runtime cookie for the array constructor vector. - // Use the "host" size and alignment, but double them to be safe regardless of - // the target. The "cookieSize" argument is used to validate this wild - // assumption until runtime interfaces are improved. + // Use pessimistic values for size and alignment that are valid for all + // supported targets. Whether the actual ArrayConstructorVector object fits + // into the available MaxArrayConstructorVectorSizeInBytes is verified when + // building clang-rt. std::size_t arrayVectorStructBitSize = - 2 * sizeof(Fortran::runtime::ArrayConstructorVector) * 8; - std::size_t alignLike = alignof(Fortran::runtime::ArrayConstructorVector) * 8; + MaxArrayConstructorVectorSizeInBytes * 8; + std::size_t alignLike = MaxArrayConstructorVectorAlignInBytes * 8; fir::SequenceType::Extent numElem = (arrayVectorStructBitSize + alignLike - 1) / alignLike; mlir::Type intType = builder.getIntegerType(alignLike); @@ -43,14 +44,12 @@ mlir::Value fir::runtime::genInitArrayConstructorVector( loc, builder); mlir::FunctionType funcType = func.getFunctionType(); cookie = builder.createConvert(loc, funcType.getInput(0), cookie); - mlir::Value cookieSize = builder.createIntegerConstant( - loc, funcType.getInput(3), numElem * alignLike / 8); mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc); mlir::Value sourceLine = - fir::factory::locationToLineNo(builder, loc, funcType.getInput(5)); + fir::factory::locationToLineNo(builder, loc, funcType.getInput(4)); auto args = fir::runtime::createArguments(builder, loc, funcType, cookie, toBox, useValueLengthParameters, - cookieSize, sourceFile, sourceLine); + sourceFile, sourceLine); builder.create(loc, func, args); return cookie; } diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 2eeb182735094f..5345d64c330f06 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -23,8 +23,8 @@ #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Support/TypeCode.h" #include "flang/Optimizer/Support/Utils.h" -#include "flang/Runtime/allocator-registry.h" -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/allocator-registry-consts.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Semantics/runtime-type-info.h" #include "mlir/Conversion/ArithCommon/AttrToLLVMConverter.h" #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" @@ -1322,16 +1322,12 @@ struct EmboxCommonConversion : public fir::FIROpConversion { insertField(rewriter, loc, descriptor, {kExtraPosInBox}, extraField); } else { // Compute the value of the extra field based on allocator_idx and - // addendum present using a Descriptor object. - Fortran::runtime::StaticDescriptor staticDescriptor; - Fortran::runtime::Descriptor &desc{staticDescriptor.descriptor()}; - desc.raw().extra = 0; - desc.SetAllocIdx(allocatorIdx); + // addendum present. + unsigned extra = allocatorIdx << _CFI_ALLOCATOR_IDX_SHIFT; if (hasAddendum) - desc.SetHasAddendum(); - descriptor = - insertField(rewriter, loc, descriptor, {kExtraPosInBox}, - this->genI32Constant(loc, rewriter, desc.raw().extra)); + extra |= _CFI_ADDENDUM_FLAG; + descriptor = insertField(rewriter, loc, descriptor, {kExtraPosInBox}, + this->genI32Constant(loc, rewriter, extra)); } if (hasAddendum) { diff --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp index 028633813a91b6..94640fa30baa54 100644 --- a/flang/lib/Semantics/compute-offsets.cpp +++ b/flang/lib/Semantics/compute-offsets.cpp @@ -11,7 +11,7 @@ #include "flang/Evaluate/fold.h" #include "flang/Evaluate/shape.h" #include "flang/Evaluate/type.h" -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" #include "flang/Semantics/scope.h" #include "flang/Semantics/semantics.h" #include "flang/Semantics/symbol.h" @@ -339,8 +339,12 @@ auto ComputeOffsetsHelper::GetSizeAndAlignment( const auto *derived{evaluate::GetDerivedTypeSpec(dyType)}; int lenParams{derived ? CountLenParameters(*derived) : 0}; bool needAddendum{derived || (dyType && dyType->IsUnlimitedPolymorphic())}; - std::size_t size{runtime::Descriptor::SizeInBytes( + + // FIXME: Get descriptor size from targetCharacteristics instead + // overapproximation + std::size_t size{runtime::MaxDescriptorSizeInBytes( symbol.Rank(), needAddendum, lenParams)}; + return {size, targetCharacteristics.descriptorAlignment()}; } if (IsProcedurePointer(symbol)) { diff --git a/flang/runtime/array-constructor.cpp b/flang/runtime/array-constructor.cpp index 3d0e969188f259..0d677d7cc63aa9 100644 --- a/flang/runtime/array-constructor.cpp +++ b/flang/runtime/array-constructor.cpp @@ -92,13 +92,10 @@ extern "C" { RT_EXT_API_GROUP_BEGIN void RTDEF(InitArrayConstructorVector)(ArrayConstructorVector &vector, - Descriptor &to, bool useValueLengthParameters, int vectorClassSize, - const char *sourceFile, int sourceLine) { + Descriptor &to, bool useValueLengthParameters, const char *sourceFile, + int sourceLine) { Terminator terminator{vector.sourceFile, vector.sourceLine}; - RUNTIME_CHECK(terminator, - to.rank() == 1 && - sizeof(ArrayConstructorVector) <= - static_cast(vectorClassSize)); + RUNTIME_CHECK(terminator, to.rank() == 1); SubscriptValue actualAllocationSize{ to.IsAllocated() ? static_cast(to.Elements()) : 0}; (void)new (&vector) ArrayConstructorVector{to, /*nextValuePosition=*/0, diff --git a/flang/runtime/environment-default-list.h b/flang/runtime/environment-default-list.h old mode 100755 new mode 100644 diff --git a/flang/runtime/internal-unit.cpp b/flang/runtime/internal-unit.cpp index f28700ee015815..f8f3877efb20ea 100644 --- a/flang/runtime/internal-unit.cpp +++ b/flang/runtime/internal-unit.cpp @@ -36,6 +36,8 @@ RT_API_ATTRS InternalDescriptorUnit::InternalDescriptorUnit( Descriptor &d{descriptor()}; RUNTIME_CHECK( terminator, that.SizeInBytes() <= d.SizeInBytes(maxRank, true, 0)); + RUNTIME_CHECK(terminator, + that.SizeInBytes() <= MaxDescriptorSizeInBytes(maxRank, true, 0)); new (&d) Descriptor{that}; d.Check(); internalIoCharKind = thatType->second; diff --git a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 index e1e65fc48babad..727eff7613e48d 100644 --- a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 @@ -17,12 +17,11 @@ subroutine test_loops() ! CHECK: fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref>>> ! CHECK: %[[VAL_7:.*]] = arith.constant false ! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr -! CHECK: %[[VAL_9:.*]] = arith.constant 80 : i32 ! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref> ! CHECK: %[[VAL_11:.*]] = arith.constant 7 : i32 ! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> ! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (!fir.ref>) -> !fir.ref -! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %[[VAL_9]], %[[VAL_13]], %[[VAL_11]]) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %[[VAL_13]], %[[VAL_11]]) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i64 ! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i64) -> index ! CHECK: %[[VAL_17:.*]] = fir.call @_QMarrayctorPibar() fastmath : () -> i32 @@ -86,7 +85,7 @@ subroutine test_arrays(a) ! CHECK: %[[VAL_26:.*]] = arith.constant false ! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> -! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_27]], %[[VAL_31]], %[[VAL_26]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_27]], %[[VAL_31]], %[[VAL_26]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.box>) -> !fir.box ! CHECK: %[[VAL_35:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_27]], %[[VAL_34]]) {{.*}}: (!fir.llvm_ptr, !fir.box) -> none ! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.box>) -> !fir.box @@ -107,7 +106,7 @@ subroutine test_arrays_unpredictable_size() ! CHECK: %[[VAL_9:.*]] = arith.constant false ! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_4]] : (!fir.ref>>>) -> !fir.ref> -! CHECK: %[[VAL_16:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_10]], %[[VAL_14]], %[[VAL_9]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_16:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_10]], %[[VAL_14]], %[[VAL_9]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: fir.call @_QMarrayctorPrank1() {{.*}}: () -> !fir.box>> ! CHECK: %[[VAL_21:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_10]], %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.box) -> none ! CHECK: fir.call @_QMarrayctorPrank3() {{.*}}: () -> !fir.box>> diff --git a/flang/test/Lower/HLFIR/array-ctor-character.f90 b/flang/test/Lower/HLFIR/array-ctor-character.f90 index 881085b370ffef..7cbad5218f5881 100644 --- a/flang/test/Lower/HLFIR/array-ctor-character.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-character.f90 @@ -52,7 +52,7 @@ subroutine test_dynamic_length() ! CHECK: %[[VAL_15:.*]] = arith.constant true ! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>>>>) -> !fir.ref> -! CHECK: %[[VAL_22:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_16]], %[[VAL_20]], %[[VAL_15]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_22:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_16]], %[[VAL_20]], %[[VAL_15]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: fir.call @_QMchararrayctorPchar_pointer( ! CHECK: fir.call @_FortranAPushArrayConstructorValue(%[[VAL_16]], %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.box) -> none ! CHECK: fir.call @_QMchararrayctorPchar_pointer( diff --git a/flang/test/Lower/HLFIR/array-ctor-derived.f90 b/flang/test/Lower/HLFIR/array-ctor-derived.f90 index 111225462a4bbe..22f7fbd72cb59f 100644 --- a/flang/test/Lower/HLFIR/array-ctor-derived.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-derived.f90 @@ -28,7 +28,7 @@ subroutine test_simple(s1, s2) ! CHECK: %[[VAL_11:.*]] = arith.constant false ! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>>>>) -> !fir.ref> -! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_4]]#1 : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_20:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_12]], %[[VAL_19]]) {{.*}}: (!fir.llvm_ptr, !fir.llvm_ptr) -> none ! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_5]]#1 : (!fir.ref>) -> !fir.llvm_ptr @@ -56,7 +56,7 @@ subroutine test_with_polymorphic(s1, s2) ! CHECK: %[[VAL_11:.*]] = arith.constant false ! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>>>>) -> !fir.ref> -! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: %[[VAL_19A:.*]] = fir.box_addr %[[VAL_4]]#1 : (!fir.class>) -> !fir.ref> ! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_19A]] : (!fir.ref>) -> !fir.llvm_ptr ! CHECK: %[[VAL_20:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_12]], %[[VAL_19]]) {{.*}}: (!fir.llvm_ptr, !fir.llvm_ptr) -> none diff --git a/flang/test/Lower/HLFIR/structure-constructor.f90 b/flang/test/Lower/HLFIR/structure-constructor.f90 index 41d08c14f5fa98..ed9ee5d0ac363b 100644 --- a/flang/test/Lower/HLFIR/structure-constructor.f90 +++ b/flang/test/Lower/HLFIR/structure-constructor.f90 @@ -273,12 +273,11 @@ end subroutine test6 ! CHECK: fir.store %[[VAL_49]] to %[[VAL_4]] : !fir.ref}>>>>> ! CHECK: %[[VAL_50:.*]] = arith.constant false ! CHECK: %[[VAL_51:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>) -> !fir.llvm_ptr -! CHECK: %[[VAL_52:.*]] = arith.constant 80 : i32 ! CHECK: %[[VAL_53:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref> ! CHECK: %[[VAL_54:.*]] = arith.constant {{[0-9]*}} : i32 ! CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_4]] : (!fir.ref}>>>>>) -> !fir.ref> ! CHECK: %[[VAL_56:.*]] = fir.convert %[[VAL_53]] : (!fir.ref>) -> !fir.ref -! CHECK: %[[VAL_57:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_51]], %[[VAL_55]], %[[VAL_50]], %[[VAL_52]], %[[VAL_56]], %[[VAL_54]]) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, i32, !fir.ref, i32) -> none +! CHECK: %[[VAL_57:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_51]], %[[VAL_55]], %[[VAL_50]], %[[VAL_56]], %[[VAL_54]]) fastmath : (!fir.llvm_ptr, !fir.ref>, i1, !fir.ref, i32) -> none ! CHECK: %[[VAL_58:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "ctor.temp"} : (!fir.ref}>>) -> (!fir.ref}>>, !fir.ref}>>) ! CHECK: %[[VAL_59:.*]] = fir.embox %[[VAL_58]]#0 : (!fir.ref}>>) -> !fir.box}>> ! CHECK: %[[VAL_60:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref> diff --git a/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp index 1db43cacc90f07..f618e72d7b7f3c 100644 --- a/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp +++ b/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp @@ -9,7 +9,7 @@ #include "flang/Optimizer/Builder/Runtime/Allocatable.h" #include "RuntimeCallTestBase.h" #include "gtest/gtest.h" -#include "flang/Runtime/descriptor.h" +#include "flang/Runtime/descriptor-consts.h" using namespace Fortran::runtime; diff --git a/flang/unittests/Runtime/ArrayConstructor.cpp b/flang/unittests/Runtime/ArrayConstructor.cpp index 9d78da79623613..62e3b780a27e72 100644 --- a/flang/unittests/Runtime/ArrayConstructor.cpp +++ b/flang/unittests/Runtime/ArrayConstructor.cpp @@ -43,8 +43,7 @@ TEST(ArrayConstructor, Basic) { result.GetDimension(0).SetBounds(1, 0); RTNAME(InitArrayConstructorVector) - (*acVector, result, /*useValueLengthParameters=*/false, - /*vectorClassSize=*/sizeof(ArrayConstructorVector)); + (*acVector, result, /*useValueLengthParameters=*/false); for (std::int32_t i{0}; i <= 99; ++i) { RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i); RTNAME(PushArrayConstructorValue)(*acVector, *x); @@ -71,8 +70,7 @@ TEST(ArrayConstructor, Basic) { // and is allocated when the first value is pushed. result.GetDimension(0).SetBounds(1, 1234); RTNAME(InitArrayConstructorVector) - (*acVector, result, /*useValueLengthParameters=*/false, - /*vectorClassSize=*/sizeof(ArrayConstructorVector)); + (*acVector, result, /*useValueLengthParameters=*/false); EXPECT_EQ(0, acVector->actualAllocationSize); std::int32_t i{42}; RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i); @@ -109,8 +107,7 @@ TEST(ArrayConstructor, Character) { static constexpr std::size_t expectedElements{10 * (1 + 4 + 2 * 3)}; result.GetDimension(0).SetBounds(1, 0); RTNAME(InitArrayConstructorVector) - (*acVector, result, /*useValueLengthParameters=*/true, - /*vectorClassSize=*/sizeof(ArrayConstructorVector)); + (*acVector, result, /*useValueLengthParameters=*/true); for (std::int32_t i{1}; i <= 10; ++i) { RTNAME(PushArrayConstructorValue)(*acVector, *c); RTNAME(PushArrayConstructorValue)(*acVector, *x); @@ -151,8 +148,7 @@ TEST(ArrayConstructor, CharacterRuntimeCheck) { result.GetDimension(0).SetBounds(1, 0); RTNAME(InitArrayConstructorVector) - (*acVector, result, /*useValueLengthParameters=*/true, - /*vectorClassSize=*/sizeof(ArrayConstructorVector)); + (*acVector, result, /*useValueLengthParameters=*/true); RTNAME(PushArrayConstructorValue)(*acVector, *c2); ASSERT_DEATH(RTNAME(PushArrayConstructorValue)(*acVector, *c3), "Array constructor: mismatched character lengths"); diff --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp index 13327964e12a48..b9407b5e7a591e 100644 --- a/flang/unittests/Runtime/ExternalIOTest.cpp +++ b/flang/unittests/Runtime/ExternalIOTest.cpp @@ -13,7 +13,7 @@ #include "CrashHandlerFixture.h" #include "gtest/gtest.h" #include "flang/Runtime/descriptor.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" #include "flang/Runtime/main.h" #include "flang/Runtime/stop.h" #include "llvm/Support/raw_ostream.h" diff --git a/flang/unittests/Runtime/ListInputTest.cpp b/flang/unittests/Runtime/ListInputTest.cpp index a4eba5283add68..38c758b7ef9662 100644 --- a/flang/unittests/Runtime/ListInputTest.cpp +++ b/flang/unittests/Runtime/ListInputTest.cpp @@ -9,7 +9,7 @@ #include "CrashHandlerFixture.h" #include "../../runtime/io-error.h" #include "flang/Runtime/descriptor.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" using namespace Fortran::runtime; using namespace Fortran::runtime::io; diff --git a/flang/unittests/Runtime/LogicalFormatTest.cpp b/flang/unittests/Runtime/LogicalFormatTest.cpp index a2c19d1e1ca948..c4fbfc81f06a43 100644 --- a/flang/unittests/Runtime/LogicalFormatTest.cpp +++ b/flang/unittests/Runtime/LogicalFormatTest.cpp @@ -8,7 +8,7 @@ #include "CrashHandlerFixture.h" #include "flang/Runtime/descriptor.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" #include #include #include diff --git a/flang/unittests/Runtime/Namelist.cpp b/flang/unittests/Runtime/Namelist.cpp index 9037fa15a97cb3..0a28f3590b86ed 100644 --- a/flang/unittests/Runtime/Namelist.cpp +++ b/flang/unittests/Runtime/Namelist.cpp @@ -10,7 +10,7 @@ #include "CrashHandlerFixture.h" #include "tools.h" #include "flang/Runtime/descriptor.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" #include #include #include diff --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang/unittests/Runtime/NumericalFormatTest.cpp index f0055153203508..274498b8e86951 100644 --- a/flang/unittests/Runtime/NumericalFormatTest.cpp +++ b/flang/unittests/Runtime/NumericalFormatTest.cpp @@ -8,7 +8,7 @@ #include "CrashHandlerFixture.h" #include "flang/Runtime/descriptor.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" #include #include #include diff --git a/flang/unittests/Runtime/RuntimeCrashTest.cpp b/flang/unittests/Runtime/RuntimeCrashTest.cpp index a649051fdca0c5..72a0b290cf8643 100644 --- a/flang/unittests/Runtime/RuntimeCrashTest.cpp +++ b/flang/unittests/Runtime/RuntimeCrashTest.cpp @@ -13,7 +13,7 @@ #include "CrashHandlerFixture.h" #include "tools.h" #include "../../runtime/terminator.h" -#include "flang/Runtime/io-api.h" +#include "flang/Runtime/io-api-consts.h" #include "flang/Runtime/transformational.h" #include