[Flang][NFC] Split runtime headers in preparation for cross-compilation. (#112188)

Split some headers into headers for public and private declarations in
preparation for #110217. Moving the runtime-private headers in
runtime-private include directory will occur in #110298.

* Do not use `sizeof(Descriptor)` in the compiler. The size of the
descriptor is target-dependent while `sizeof(Descriptor)` is the size of
the Descriptor for the host platform which might be too small when
cross-compiling to a different platform. Another problem is that the
emitted assembly ((cross-)compiling to the same target) is not identical
between Flang's running on different systems. Moving the declaration of
`class Descriptor` out of the included header will also reduce the
amount of #included sources.

* Do not use `sizeof(ArrayConstructorVector)` and
`alignof(ArrayConstructorVector)` in the compiler. Same reason as with
`Descriptor`.

* Compute the descriptor's extra flags without instantiating a
Descriptor. `Fortran::runtime::Descriptor` is defined in the runtime
source, but not the compiler source.

* Move `InquiryKeywordHashDecode` into runtime-private header. The
function is defined in the runtime sources and trying to call it in the
compiler would lead to a link-error.

* Move allocator-kind magic numbers into common header. They are the
only declarations out of `allocator-registry.h` in the compiler as well.
 
This does not make Flang cross-compile ready yet, the main goal is to
avoid transitive header dependencies from Flang to clang-rt. There are
more assumptions that host platform is the same as the target platform.
This commit is contained in:
Michael Kruse
2024-12-06 15:29:00 +01:00
committed by GitHub
parent 1801fb4bd3
commit c91ba04328
41 changed files with 728 additions and 567 deletions

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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

View File

@@ -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 <cstddef>

View File

@@ -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 <cstddef>

View File

@@ -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_ */

View File

@@ -10,18 +10,11 @@
#define FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_H_
#include "flang/Common/api-attrs.h"
#include "flang/Runtime/allocator-registry-consts.h"
#include <cstdint>
#include <cstdlib>
#include <vector>
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 {

View File

@@ -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 <cstdint>
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_ */

View File

@@ -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 <cstdint>
@@ -43,76 +44,14 @@ private:
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.
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");
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);
// 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_

View File

@@ -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 <cstddef>
#include <cstdint>
// 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<std::size_t>(lengthTypeParameters) * 8u;
}
return bytes;
}
} // namespace Fortran::runtime
#endif /* FORTRAN_RUNTIME_DESCRIPTOR_CONSTS_H_ */

View File

@@ -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 <algorithm>
@@ -28,14 +29,8 @@
#include <cstdio>
#include <cstring>
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 @@ public:
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 @@ public:
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() {

View File

@@ -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 <cinttypes>
#include <cstddef>
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_ */

View File

@@ -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 <cinttypes>
#include <cstddef>
@@ -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

View File

@@ -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_

View File

@@ -11,84 +11,12 @@
#ifndef FORTRAN_RUNTIME_IOSTAT_H_
#define FORTRAN_RUNTIME_IOSTAT_H_
#include "flang/Common/api-attrs.h"
#include "flang/Runtime/magic-numbers.h"
#include "flang/Runtime/iostat-consts.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,
};
RT_API_ATTRS const char *IostatErrorString(int);
} // namespace Fortran::runtime::io

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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<fir::CallOp>(loc, func, args);
return cookie;
}

View File

@@ -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<OP> {
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) {

View File

@@ -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)) {

View File

@@ -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<std::size_t>(vectorClassSize));
RUNTIME_CHECK(terminator, to.rank() == 1);
SubscriptValue actualAllocationSize{
to.IsAllocated() ? static_cast<SubscriptValue>(to.Elements()) : 0};
(void)new (&vector) ArrayConstructorVector{to, /*nextValuePosition=*/0,

0
flang/runtime/environment-default-list.h Executable file → Normal file
View File

View File

@@ -36,6 +36,8 @@ RT_API_ATTRS InternalDescriptorUnit<DIR>::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;

View File

@@ -17,12 +17,11 @@ end subroutine
! CHECK: fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: %[[VAL_7:.*]] = arith.constant false
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_9:.*]] = arith.constant 80 : i32
! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>
! CHECK: %[[VAL_11:.*]] = arith.constant 7 : i32
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<!fir.char<1,{{[0-9]*}}>>) -> !fir.ref<i8>
! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %[[VAL_9]], %[[VAL_13]], %[[VAL_11]]) fastmath<contract> : (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %[[VAL_13]], %[[VAL_11]]) fastmath<contract> : (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, 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<contract> : () -> i32
@@ -86,7 +85,7 @@ end subroutine
! CHECK: %[[VAL_26:.*]] = arith.constant false
! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_27]], %[[VAL_31]], %[[VAL_26]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_27]], %[[VAL_31]], %[[VAL_26]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.box<!fir.array<?x?xi32>>) -> !fir.box<none>
! CHECK: %[[VAL_35:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_27]], %[[VAL_34]]) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.box<!fir.array<?x?xi32>>) -> !fir.box<none>
@@ -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.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_16:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_10]], %[[VAL_14]], %[[VAL_9]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_16:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_10]], %[[VAL_14]], %[[VAL_9]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, i32) -> none
! CHECK: fir.call @_QMarrayctorPrank1() {{.*}}: () -> !fir.box<!fir.heap<!fir.array<?xi32>>>
! CHECK: %[[VAL_21:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_10]], %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
! CHECK: fir.call @_QMarrayctorPrank3() {{.*}}: () -> !fir.box<!fir.heap<!fir.array<?x?x?xi32>>>

View File

@@ -52,7 +52,7 @@ contains
! CHECK: %[[VAL_15:.*]] = arith.constant true
! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<2x!fir.char<1,?>>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_22:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_16]], %[[VAL_20]], %[[VAL_15]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_22:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_16]], %[[VAL_20]], %[[VAL_15]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, i32) -> none
! CHECK: fir.call @_QMchararrayctorPchar_pointer(
! CHECK: fir.call @_FortranAPushArrayConstructorValue(%[[VAL_16]], %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
! CHECK: fir.call @_QMchararrayctorPchar_pointer(

View File

@@ -28,7 +28,7 @@ contains
! CHECK: %[[VAL_11:.*]] = arith.constant false
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<2x!fir.type<_QMtypesTsimple{i:i32,j:i32}>>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_4]]#1 : (!fir.ref<!fir.type<_QMtypesTsimple{i:i32,j:i32}>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_20:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_12]], %[[VAL_19]]) {{.*}}: (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>) -> none
! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_5]]#1 : (!fir.ref<!fir.type<_QMtypesTsimple{i:i32,j:i32}>>) -> !fir.llvm_ptr<i8>
@@ -56,7 +56,7 @@ contains
! CHECK: %[[VAL_11:.*]] = arith.constant false
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<2x!fir.type<_QMtypesTsimple{i:i32,j:i32}>>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_12]], %[[VAL_16]], %[[VAL_11]], %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_19A:.*]] = fir.box_addr %[[VAL_4]]#1 : (!fir.class<!fir.type<_QMtypesTsimple{i:i32,j:i32}>>) -> !fir.ref<!fir.type<_QMtypesTsimple{i:i32,j:i32}>>
! CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_19A]] : (!fir.ref<!fir.type<_QMtypesTsimple{i:i32,j:i32}>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_20:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_12]], %[[VAL_19]]) {{.*}}: (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>) -> none

View File

@@ -273,12 +273,11 @@ end subroutine test6
! CHECK: fir.store %[[VAL_49]] to %[[VAL_4]] : !fir.ref<!fir.box<!fir.heap<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>>>
! CHECK: %[[VAL_50:.*]] = arith.constant false
! CHECK: %[[VAL_51:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_52:.*]] = arith.constant 80 : i32
! CHECK: %[[VAL_53:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>
! CHECK: %[[VAL_54:.*]] = arith.constant {{[0-9]*}} : i32
! CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[VAL_56:.*]] = fir.convert %[[VAL_53]] : (!fir.ref<!fir.char<1,{{[0-9]*}}>>) -> !fir.ref<i8>
! CHECK: %[[VAL_57:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_51]], %[[VAL_55]], %[[VAL_50]], %[[VAL_52]], %[[VAL_56]], %[[VAL_54]]) fastmath<contract> : (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_57:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_51]], %[[VAL_55]], %[[VAL_50]], %[[VAL_56]], %[[VAL_54]]) fastmath<contract> : (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_58:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "ctor.temp"} : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>) -> (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>)
! CHECK: %[[VAL_59:.*]] = fir.embox %[[VAL_58]]#0 : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>) -> !fir.box<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
! CHECK: %[[VAL_60:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref<!fir.char<1,{{[0-9]*}}>>

View File

@@ -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;

View File

@@ -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");

View File

@@ -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"

View File

@@ -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;

View File

@@ -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 <algorithm>
#include <array>
#include <cstring>

View File

@@ -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 <algorithm>
#include <cinttypes>
#include <complex>

View File

@@ -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 <algorithm>
#include <array>
#include <cstring>

View File

@@ -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 <gtest/gtest.h>