[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:
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
20
flang/include/flang/Runtime/allocator-registry-consts.h
Normal file
20
flang/include/flang/Runtime/allocator-registry-consts.h
Normal 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_ */
|
||||
@@ -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 {
|
||||
|
||||
97
flang/include/flang/Runtime/array-constructor-consts.h
Normal file
97
flang/include/flang/Runtime/array-constructor-consts.h
Normal 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_ */
|
||||
@@ -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_
|
||||
|
||||
74
flang/include/flang/Runtime/descriptor-consts.h
Normal file
74
flang/include/flang/Runtime/descriptor-consts.h
Normal 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_ */
|
||||
@@ -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() {
|
||||
|
||||
368
flang/include/flang/Runtime/io-api-consts.h
Normal file
368
flang/include/flang/Runtime/io-api-consts.h
Normal 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_ */
|
||||
@@ -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
|
||||
|
||||
93
flang/include/flang/Runtime/iostat-consts.h
Normal file
93
flang/include/flang/Runtime/iostat-consts.h
Normal 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_
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
0
flang/runtime/environment-default-list.h
Executable file → Normal 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;
|
||||
|
||||
@@ -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>>>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]*}}>>
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user