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

via flang-commits flang-commits at lists.llvm.org
Fri Dec 6 06:29:03 PST 2024


Author: Michael Kruse
Date: 2024-12-06T15:29:00+01:00
New Revision: c91ba04328e1ded6f284469a7828d181324d4e30

URL: https://github.com/llvm/llvm-project/commit/c91ba04328e1ded6f284469a7828d181324d4e30
DIFF: https://github.com/llvm/llvm-project/commit/c91ba04328e1ded6f284469a7828d181324d4e30.diff

LOG: [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.

Added: 
    flang/include/flang/Runtime/allocator-registry-consts.h
    flang/include/flang/Runtime/array-constructor-consts.h
    flang/include/flang/Runtime/descriptor-consts.h
    flang/include/flang/Runtime/io-api-consts.h
    flang/include/flang/Runtime/iostat-consts.h

Modified: 
    flang/include/flang/Lower/Allocatable.h
    flang/include/flang/Optimizer/Builder/IntrinsicCall.h
    flang/include/flang/Optimizer/Builder/MutableBox.h
    flang/include/flang/Optimizer/CodeGen/DescriptorModel.h
    flang/include/flang/Runtime/CUDA/allocatable.h
    flang/include/flang/Runtime/CUDA/allocator.h
    flang/include/flang/Runtime/CUDA/common.h
    flang/include/flang/Runtime/CUDA/descriptor.h
    flang/include/flang/Runtime/CUDA/memory.h
    flang/include/flang/Runtime/allocator-registry.h
    flang/include/flang/Runtime/array-constructor.h
    flang/include/flang/Runtime/descriptor.h
    flang/include/flang/Runtime/io-api.h
    flang/include/flang/Runtime/iostat.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Lower/ConvertVariable.cpp
    flang/lib/Lower/IO.cpp
    flang/lib/Optimizer/Builder/IntrinsicCall.cpp
    flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/lib/Semantics/compute-offsets.cpp
    flang/runtime/array-constructor.cpp
    flang/runtime/environment-default-list.h
    flang/runtime/internal-unit.cpp
    flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90
    flang/test/Lower/HLFIR/array-ctor-character.f90
    flang/test/Lower/HLFIR/array-ctor-derived.f90
    flang/test/Lower/HLFIR/structure-constructor.f90
    flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp
    flang/unittests/Runtime/ArrayConstructor.cpp
    flang/unittests/Runtime/ExternalIOTest.cpp
    flang/unittests/Runtime/ListInputTest.cpp
    flang/unittests/Runtime/LogicalFormatTest.cpp
    flang/unittests/Runtime/Namelist.cpp
    flang/unittests/Runtime/NumericalFormatTest.cpp
    flang/unittests/Runtime/RuntimeCrashTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/Allocatable.h b/flang/include/flang/Lower/Allocatable.h
index 1209b157ed1f41..0e89af94af40f6 100644
--- a/flang/include/flang/Lower/Allocatable.h
+++ b/flang/include/flang/Lower/Allocatable.h
@@ -15,7 +15,7 @@
 
 #include "flang/Lower/AbstractConverter.h"
 #include "flang/Optimizer/Builder/MutableBox.h"
-#include "flang/Runtime/allocator-registry.h"
+#include "flang/Runtime/allocator-registry-consts.h"
 #include "llvm/ADT/StringRef.h"
 
 namespace mlir {

diff  --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index e7955c2fc0314d..bc0020e614db24 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -16,7 +16,7 @@
 #include "flang/Optimizer/Builder/Runtime/Numeric.h"
 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
 #include "flang/Runtime/entry-names.h"
-#include "flang/Runtime/iostat.h"
+#include "flang/Runtime/iostat-consts.h"
 #include "mlir/Dialect/Complex/IR/Complex.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/Dialect/Math/IR/Math.h"

diff  --git a/flang/include/flang/Optimizer/Builder/MutableBox.h b/flang/include/flang/Optimizer/Builder/MutableBox.h
index fea7c7204837b4..39657ddaf6e03a 100644
--- a/flang/include/flang/Optimizer/Builder/MutableBox.h
+++ b/flang/include/flang/Optimizer/Builder/MutableBox.h
@@ -14,7 +14,7 @@
 #define FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H
 
 #include "flang/Optimizer/Builder/BoxValue.h"
-#include "flang/Runtime/allocator-registry.h"
+#include "flang/Runtime/allocator-registry-consts.h"
 #include "llvm/ADT/StringRef.h"
 
 namespace mlir {

diff  --git a/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h b/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h
index ff0cf29e8073e6..9cccf8db87270e 100644
--- a/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h
+++ b/flang/include/flang/Optimizer/CodeGen/DescriptorModel.h
@@ -23,7 +23,7 @@
 #define OPTIMIZER_DESCRIPTOR_MODEL_H
 
 #include "flang/ISO_Fortran_binding_wrapper.h"
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "llvm/Support/ErrorHandling.h"

diff  --git a/flang/include/flang/Runtime/CUDA/allocatable.h b/flang/include/flang/Runtime/CUDA/allocatable.h
index e2156281d1b2b0..0a96f73b6be44b 100644
--- a/flang/include/flang/Runtime/CUDA/allocatable.h
+++ b/flang/include/flang/Runtime/CUDA/allocatable.h
@@ -9,7 +9,7 @@
 #ifndef FORTRAN_RUNTIME_CUDA_ALLOCATABLE_H_
 #define FORTRAN_RUNTIME_CUDA_ALLOCATABLE_H_
 
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Runtime/entry-names.h"
 
 namespace Fortran::runtime::cuda {

diff  --git a/flang/include/flang/Runtime/CUDA/allocator.h b/flang/include/flang/Runtime/CUDA/allocator.h
index 618da44c675d85..b6f0e7f303176c 100644
--- a/flang/include/flang/Runtime/CUDA/allocator.h
+++ b/flang/include/flang/Runtime/CUDA/allocator.h
@@ -10,7 +10,7 @@
 #define FORTRAN_RUNTIME_CUDA_ALLOCATOR_H_
 
 #include "common.h"
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Runtime/entry-names.h"
 
 namespace Fortran::runtime::cuda {

diff  --git a/flang/include/flang/Runtime/CUDA/common.h b/flang/include/flang/Runtime/CUDA/common.h
index 8172ea39a14f84..9c95f727ee6734 100644
--- a/flang/include/flang/Runtime/CUDA/common.h
+++ b/flang/include/flang/Runtime/CUDA/common.h
@@ -9,7 +9,7 @@
 #ifndef FORTRAN_RUNTIME_CUDA_COMMON_H_
 #define FORTRAN_RUNTIME_CUDA_COMMON_H_
 
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Runtime/entry-names.h"
 
 /// Type of memory for allocation/deallocation

diff  --git a/flang/include/flang/Runtime/CUDA/descriptor.h b/flang/include/flang/Runtime/CUDA/descriptor.h
index 93791012fdcc73..4c6c2c4694fd43 100644
--- a/flang/include/flang/Runtime/CUDA/descriptor.h
+++ b/flang/include/flang/Runtime/CUDA/descriptor.h
@@ -9,7 +9,7 @@
 #ifndef FORTRAN_RUNTIME_CUDA_DESCRIPTOR_H_
 #define FORTRAN_RUNTIME_CUDA_DESCRIPTOR_H_
 
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Runtime/entry-names.h"
 #include <cstddef>
 

diff  --git a/flang/include/flang/Runtime/CUDA/memory.h b/flang/include/flang/Runtime/CUDA/memory.h
index 2bb083b0dd75cb..fbe4941260ff92 100644
--- a/flang/include/flang/Runtime/CUDA/memory.h
+++ b/flang/include/flang/Runtime/CUDA/memory.h
@@ -9,7 +9,7 @@
 #ifndef FORTRAN_RUNTIME_CUDA_MEMORY_H_
 #define FORTRAN_RUNTIME_CUDA_MEMORY_H_
 
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Runtime/entry-names.h"
 #include <cstddef>
 

diff  --git a/flang/include/flang/Runtime/allocator-registry-consts.h b/flang/include/flang/Runtime/allocator-registry-consts.h
new file mode 100644
index 00000000000000..70735c2fc7a71c
--- /dev/null
+++ b/flang/include/flang/Runtime/allocator-registry-consts.h
@@ -0,0 +1,20 @@
+//===-- include/flang/Runtime/allocator-registry-consts.h -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_CONSTS_H_
+#define FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_CONSTS_H_
+
+static constexpr unsigned kDefaultAllocator = 0;
+
+// Allocator used for CUF
+static constexpr unsigned kPinnedAllocatorPos = 1;
+static constexpr unsigned kDeviceAllocatorPos = 2;
+static constexpr unsigned kManagedAllocatorPos = 3;
+static constexpr unsigned kUnifiedAllocatorPos = 4;
+
+#endif /* FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_CONSTS_H_ */

diff  --git a/flang/include/flang/Runtime/allocator-registry.h b/flang/include/flang/Runtime/allocator-registry.h
index 771fa8a9a9933c..4c3295edf13d9a 100644
--- a/flang/include/flang/Runtime/allocator-registry.h
+++ b/flang/include/flang/Runtime/allocator-registry.h
@@ -10,18 +10,11 @@
 #define FORTRAN_RUNTIME_ALLOCATOR_REGISTRY_H_
 
 #include "flang/Common/api-attrs.h"
+#include "flang/Runtime/allocator-registry-consts.h"
 #include <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 {

diff  --git a/flang/include/flang/Runtime/array-constructor-consts.h b/flang/include/flang/Runtime/array-constructor-consts.h
new file mode 100644
index 00000000000000..ad3583eef29aad
--- /dev/null
+++ b/flang/include/flang/Runtime/array-constructor-consts.h
@@ -0,0 +1,97 @@
+//===-- include/flang/Runtime/array-constructor-consts.h --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_RUNTIME_ARRAY_CONSTRUCTOR_CONSTS_H_
+#define FORTRAN_RUNTIME_ARRAY_CONSTRUCTOR_CONSTS_H_
+
+#include "flang/Runtime/descriptor-consts.h"
+#include "flang/Runtime/entry-names.h"
+#include <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
+//  
diff erent character length than the array constructor values.
+
+extern "C" {
+// API to initialize an ArrayConstructorVector before any values are pushed to
+// it. Inlined code is only expected to allocate the "ArrayConstructorVector"
+// class instance storage with sufficient size
+// (MaxArrayConstructorVectorSizeInBytes is expected to be large enough for all
+// supported targets). This avoids the need for the runtime to maintain a state,
+// or to use dynamic allocation for it.
+void RTDECL(InitArrayConstructorVector)(ArrayConstructorVector &vector,
+    Descriptor &to, bool useValueLengthParameters,
+    const char *sourceFile = nullptr, int sourceLine = 0);
+
+// Generic API to push any kind of entity into the array constructor (any
+// Fortran type and any rank).
+void RTDECL(PushArrayConstructorValue)(
+    ArrayConstructorVector &vector, const Descriptor &from);
+
+// API to push scalar array constructor value of:
+//   - a numerical or logical type,
+//   - or a derived type that has no length parameters, and no allocatable
+//   component (that would require deep copies).
+// It requires no descriptor for the value that is passed via its base address.
+void RTDECL(PushArrayConstructorSimpleScalar)(
+    ArrayConstructorVector &vector, void *from);
+} // extern "C"
+} // namespace Fortran::runtime
+
+#endif /* FORTRAN_RUNTIME_ARRAY_CONSTRUCTOR_CONSTS_H_ */

diff  --git a/flang/include/flang/Runtime/array-constructor.h b/flang/include/flang/Runtime/array-constructor.h
index 46fc0418c7991e..2f6aaae17c6508 100644
--- a/flang/include/flang/Runtime/array-constructor.h
+++ b/flang/include/flang/Runtime/array-constructor.h
@@ -12,6 +12,7 @@
 #ifndef FORTRAN_RUNTIME_ARRAYCONSTRUCTOR_H_
 #define FORTRAN_RUNTIME_ARRAYCONSTRUCTOR_H_
 
+#include "flang/Runtime/array-constructor-consts.h"
 #include "flang/Runtime/descriptor.h"
 #include "flang/Runtime/entry-names.h"
 #include <cstdint>
@@ -43,76 +44,14 @@ struct ArrayConstructorVector {
   unsigned char useValueLengthParameters_ : 1;
 };
 
-// This file defines an API to "push" an evaluated array constructor value
-// "from" into some storage "to" of an array constructor. It can be seen as a
-// form of std::vector::push_back() implementation for Fortran array
-// constructors. In the APIs and ArrayConstructorVector struct above:
-//
-// - "to" is a ranked-1 descriptor whose declared type is already set to the
-// array constructor derived type. It may be already allocated, even before the
-// first call to this API, or it may be unallocated. "to" extent is increased
-// every time a "from" is pushed past its current extent. At this end of the
-// API calls, its extent is the extent of the array constructor. If "to" is
-// unallocated and its extent is not null, it is assumed this is the final array
-// constructor extent value, and the first allocation already "reserves" storage
-// space accordingly to avoid reallocations.
-//  - "from" is a scalar or array descriptor for the evaluated array
-//  constructor value that must be copied into the storage of "to" at
-//  "nextValuePosition".
-//  - "useValueLengthParameters" must be set to true if the array constructor
-//  has length parameters and no type spec. If it is true and "to" is
-//  unallocated, "to" will take the length parameters of "from". If it is true
-//  and "to" is an allocated character array constructor, it will be checked
-//  that "from" length matches the one from "to". When it is false, the
-//  character length must already be set in "to" before the first call to this
-//  API and "from" character lengths are allowed to mismatch from "to".
-// - "nextValuePosition" is the zero based sequence position of "from" in the
-// array constructor. It is updated after this call by the number of "from"
-// elements. It should be set to zero by the caller of this API before the first
-// call.
-// - "actualAllocationSize" is the current allocation size of "to" storage. It
-// may be bigger than "to" extent for reallocation optimization purposes, but
-// should never be smaller, unless this is the first call and "to" is
-// unallocated. It is updated by the runtime after each successful allocation or
-// reallocation. It should be set to "to" extent if "to" is allocated before the
-// first call of this API, and can be left undefined otherwise.
-//
-// Note that this API can be used with "to" being a variable (that can be
-// discontiguous). This can be done when the variable is the left hand side of
-// an assignment from an array constructor as long as:
-//  - none of the ac-value overlaps with the variable,
-//  - this is an intrinsic assignment that is not a whole allocatable
-//  assignment, *and* for a type that has no components requiring user defined
-//  assignments,
-//  - the variable is properly finalized before using this API if its need to,
-//  - "useValueLengthParameters" should be set to false in this case, even if
-//  the array constructor has no type-spec, since the variable may have a
-//  
diff erent character length than the array constructor values.
-
-extern "C" {
-// API to initialize an ArrayConstructorVector before any values are pushed to
-// it. Inlined code is only expected to allocate the "ArrayConstructorVector"
-// class instance storage with sufficient size (using
-// "2*sizeof(ArrayConstructorVector)" on the host should be safe regardless of
-// the target the runtime is compiled for). This avoids the need for the runtime
-// to maintain a state, or to use dynamic allocation for it. "vectorClassSize"
-// is used to validate that lowering allocated enough space for it.
-void RTDECL(InitArrayConstructorVector)(ArrayConstructorVector &vector,
-    Descriptor &to, bool useValueLengthParameters, int vectorClassSize,
-    const char *sourceFile = nullptr, int sourceLine = 0);
-
-// Generic API to push any kind of entity into the array constructor (any
-// Fortran type and any rank).
-void RTDECL(PushArrayConstructorValue)(
-    ArrayConstructorVector &vector, const Descriptor &from);
+static_assert(sizeof(Fortran::runtime::ArrayConstructorVector) <=
+        MaxArrayConstructorVectorSizeInBytes,
+    "ABI requires sizeof(ArrayConstructorVector) to be smaller than "
+    "MaxArrayConstructorVectorSizeInBytes");
+static_assert(alignof(Fortran::runtime::ArrayConstructorVector) <=
+        MaxArrayConstructorVectorAlignInBytes,
+    "ABI requires alignof(ArrayConstructorVector) to be smaller than "
+    "MaxArrayConstructorVectorAlignInBytes");
 
-// API to push scalar array constructor value of:
-//   - a numerical or logical type,
-//   - or a derived type that has no length parameters, and no allocatable
-//   component (that would require deep copies).
-// It requires no descriptor for the value that is passed via its base address.
-void RTDECL(PushArrayConstructorSimpleScalar)(
-    ArrayConstructorVector &vector, void *from);
-} // extern "C"
 } // namespace Fortran::runtime
 #endif // FORTRAN_RUNTIME_ARRAYCONSTRUCTOR_H_

diff  --git a/flang/include/flang/Runtime/descriptor-consts.h b/flang/include/flang/Runtime/descriptor-consts.h
new file mode 100644
index 00000000000000..3b2537579d5864
--- /dev/null
+++ b/flang/include/flang/Runtime/descriptor-consts.h
@@ -0,0 +1,74 @@
+//===-- include/flang/Runtime/descriptor-consts.h ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_RUNTIME_DESCRIPTOR_CONSTS_H_
+#define FORTRAN_RUNTIME_DESCRIPTOR_CONSTS_H_
+
+#include "flang/Common/api-attrs.h"
+#include "flang/ISO_Fortran_binding_wrapper.h"
+#include <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; (ptr
diff _t -> up to 8 bytes)
+  //     CFI_index_t extent;      (ptr
diff _t -> up to 8 bytes)
+  //     CFI_index_t sm;          (ptr
diff _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_ */

diff  --git a/flang/include/flang/Runtime/descriptor.h b/flang/include/flang/Runtime/descriptor.h
index e6300accfeac08..44e82c6a256873 100644
--- a/flang/include/flang/Runtime/descriptor.h
+++ b/flang/include/flang/Runtime/descriptor.h
@@ -19,6 +19,7 @@
 // but should never reference this internal header.
 
 #include "flang/ISO_Fortran_binding_wrapper.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Runtime/memory.h"
 #include "flang/Runtime/type-code.h"
 #include <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 @@ class Descriptor {
 
   void Dump(FILE * = stdout) const;
 
-// Value of the addendum presence flag.
-#define _CFI_ADDENDUM_FLAG 1
-// Number of bits needed to be shifted when manipulating the allocator index.
-#define _CFI_ALLOCATOR_IDX_SHIFT 1
-// Allocator index mask.
-#define _CFI_ALLOCATOR_IDX_MASK 0b00001110
-
   RT_API_ATTRS inline bool HasAddendum() const {
     return raw_.extra & _CFI_ADDENDUM_FLAG;
   }
@@ -464,6 +452,8 @@ class alignas(Descriptor) StaticDescriptor {
   static constexpr bool hasAddendum{ADDENDUM || MAX_LEN_PARMS > 0};
   static constexpr std::size_t byteSize{
       Descriptor::SizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)};
+  static_assert(byteSize <=
+      MaxDescriptorSizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters));
   RT_OFFLOAD_VAR_GROUP_END
 
   RT_API_ATTRS Descriptor &descriptor() {

diff  --git a/flang/include/flang/Runtime/io-api-consts.h b/flang/include/flang/Runtime/io-api-consts.h
new file mode 100644
index 00000000000000..7ed8bf1489b3c2
--- /dev/null
+++ b/flang/include/flang/Runtime/io-api-consts.h
@@ -0,0 +1,368 @@
+//===-- include/flang/Runtime/io-api-consts.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_RUNTIME_IO_API_CONSTS_H_
+#define FORTRAN_RUNTIME_IO_API_CONSTS_H_
+
+#include "flang/Common/uint128.h"
+#include "flang/Runtime/entry-names.h"
+#include "flang/Runtime/iostat-consts.h"
+#include "flang/Runtime/magic-numbers.h"
+#include <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_ */

diff  --git a/flang/include/flang/Runtime/io-api.h b/flang/include/flang/Runtime/io-api.h
index 328afc715a3f1e..b86c3cecb32c5a 100644
--- a/flang/include/flang/Runtime/io-api.h
+++ b/flang/include/flang/Runtime/io-api.h
@@ -13,7 +13,8 @@
 
 #include "flang/Common/uint128.h"
 #include "flang/Runtime/entry-names.h"
-#include "flang/Runtime/iostat.h"
+#include "flang/Runtime/io-api-consts.h"
+#include "flang/Runtime/iostat-consts.h"
 #include "flang/Runtime/magic-numbers.h"
 #include <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

diff  --git a/flang/include/flang/Runtime/iostat-consts.h b/flang/include/flang/Runtime/iostat-consts.h
new file mode 100644
index 00000000000000..26bf75f59fa0d6
--- /dev/null
+++ b/flang/include/flang/Runtime/iostat-consts.h
@@ -0,0 +1,93 @@
+//===-- include/flang/Runtime/iostat-consts.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_RUNTIME_IOSTAT_CONSTS_H_
+#define FORTRAN_RUNTIME_IOSTAT_CONSTS_H_
+
+#include "flang/Common/api-attrs.h"
+#include "flang/Runtime/magic-numbers.h"
+
+namespace Fortran::runtime::io {
+
+// The value of IOSTAT= is zero when no error, end-of-record,
+// or end-of-file condition has arisen; errors are positive values.
+// (See 12.11.5 in Fortran 2018 for the complete requirements;
+// these constants must match the values of their corresponding
+// named constants in the predefined module ISO_FORTRAN_ENV, so
+// they're actually defined in another magic-numbers.h header file
+// so that they can be included both here and there.)
+enum Iostat {
+  IostatOk = 0, // no error, EOF, or EOR condition
+
+  // These error codes are required by Fortran (see 12.10.2.16-17) to be
+  // negative integer values
+  IostatEnd = FORTRAN_RUNTIME_IOSTAT_END, // end-of-file on input & no error
+  // End-of-record on non-advancing input, no EOF or error
+  IostatEor = FORTRAN_RUNTIME_IOSTAT_EOR,
+
+  // This value is also required to be negative (12.11.5 bullet 6).
+  // It signifies a FLUSH statement on an unflushable unit.
+  IostatUnflushable = FORTRAN_RUNTIME_IOSTAT_FLUSH,
+
+  // Other errors are positive.  We use "errno" values unchanged.
+  // This error is exported in ISO_Fortran_env.
+  IostatInquireInternalUnit = FORTRAN_RUNTIME_IOSTAT_INQUIRE_INTERNAL_UNIT,
+
+  // The remaining error codes are not exported.
+  IostatGenericError = 1001, // see IOMSG= for details
+  IostatRecordWriteOverrun,
+  IostatRecordReadOverrun,
+  IostatInternalWriteOverrun,
+  IostatErrorInFormat,
+  IostatErrorInKeyword,
+  IostatEndfileDirect,
+  IostatEndfileUnwritable,
+  IostatOpenBadRecl,
+  IostatOpenUnknownSize,
+  IostatOpenBadAppend,
+  IostatWriteToReadOnly,
+  IostatReadFromWriteOnly,
+  IostatBackspaceNonSequential,
+  IostatBackspaceAtFirstRecord,
+  IostatRewindNonSequential,
+  IostatWriteAfterEndfile,
+  IostatFormattedIoOnUnformattedUnit,
+  IostatUnformattedIoOnFormattedUnit,
+  IostatListIoOnDirectAccessUnit,
+  IostatUnformattedChildOnFormattedParent,
+  IostatFormattedChildOnUnformattedParent,
+  IostatChildInputFromOutputParent,
+  IostatChildOutputToInputParent,
+  IostatShortRead,
+  IostatMissingTerminator,
+  IostatBadUnformattedRecord,
+  IostatUTF8Decoding,
+  IostatUnitOverflow,
+  IostatBadRealInput,
+  IostatBadScaleFactor,
+  IostatBadAsynchronous,
+  IostatBadWaitUnit,
+  IostatBOZInputOverflow,
+  IostatIntegerInputOverflow,
+  IostatRealInputOverflow,
+  IostatOpenAlreadyConnected,
+  IostatCannotReposition,
+  IostatBadWaitId,
+  IostatTooManyAsyncOps,
+  IostatBadBackspaceUnit,
+  IostatBadUnitNumber,
+  IostatBadFlushUnit,
+  IostatBadOpOnChildUnit,
+  IostatBadNewUnit,
+  IostatBadListDirectedInputSeparator,
+  IostatNonExternalDefinedUnformattedIo,
+};
+
+} // namespace Fortran::runtime::io
+
+#endif // FORTRAN_RUNTIME_IOSTAT_CONSTS_H_

diff  --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h
index 6ce7c82b424eb7..d8db68a3a1c2ee 100644
--- a/flang/include/flang/Runtime/iostat.h
+++ b/flang/include/flang/Runtime/iostat.h
@@ -11,83 +11,11 @@
 
 #ifndef FORTRAN_RUNTIME_IOSTAT_H_
 #define FORTRAN_RUNTIME_IOSTAT_H_
-#include "flang/Common/api-attrs.h"
-#include "flang/Runtime/magic-numbers.h"
-namespace Fortran::runtime::io {
-
-// The value of IOSTAT= is zero when no error, end-of-record,
-// or end-of-file condition has arisen; errors are positive values.
-// (See 12.11.5 in Fortran 2018 for the complete requirements;
-// these constants must match the values of their corresponding
-// named constants in the predefined module ISO_FORTRAN_ENV, so
-// they're actually defined in another magic-numbers.h header file
-// so that they can be included both here and there.)
-enum Iostat {
-  IostatOk = 0, // no error, EOF, or EOR condition
-
-  // These error codes are required by Fortran (see 12.10.2.16-17) to be
-  // negative integer values
-  IostatEnd = FORTRAN_RUNTIME_IOSTAT_END, // end-of-file on input & no error
-  // End-of-record on non-advancing input, no EOF or error
-  IostatEor = FORTRAN_RUNTIME_IOSTAT_EOR,
 
-  // This value is also required to be negative (12.11.5 bullet 6).
-  // It signifies a FLUSH statement on an unflushable unit.
-  IostatUnflushable = FORTRAN_RUNTIME_IOSTAT_FLUSH,
-
-  // Other errors are positive.  We use "errno" values unchanged.
-  // This error is exported in ISO_Fortran_env.
-  IostatInquireInternalUnit = FORTRAN_RUNTIME_IOSTAT_INQUIRE_INTERNAL_UNIT,
+#include "flang/Common/api-attrs.h"
+#include "flang/Runtime/iostat-consts.h"
 
-  // The remaining error codes are not exported.
-  IostatGenericError = 1001, // see IOMSG= for details
-  IostatRecordWriteOverrun,
-  IostatRecordReadOverrun,
-  IostatInternalWriteOverrun,
-  IostatErrorInFormat,
-  IostatErrorInKeyword,
-  IostatEndfileDirect,
-  IostatEndfileUnwritable,
-  IostatOpenBadRecl,
-  IostatOpenUnknownSize,
-  IostatOpenBadAppend,
-  IostatWriteToReadOnly,
-  IostatReadFromWriteOnly,
-  IostatBackspaceNonSequential,
-  IostatBackspaceAtFirstRecord,
-  IostatRewindNonSequential,
-  IostatWriteAfterEndfile,
-  IostatFormattedIoOnUnformattedUnit,
-  IostatUnformattedIoOnFormattedUnit,
-  IostatListIoOnDirectAccessUnit,
-  IostatUnformattedChildOnFormattedParent,
-  IostatFormattedChildOnUnformattedParent,
-  IostatChildInputFromOutputParent,
-  IostatChildOutputToInputParent,
-  IostatShortRead,
-  IostatMissingTerminator,
-  IostatBadUnformattedRecord,
-  IostatUTF8Decoding,
-  IostatUnitOverflow,
-  IostatBadRealInput,
-  IostatBadScaleFactor,
-  IostatBadAsynchronous,
-  IostatBadWaitUnit,
-  IostatBOZInputOverflow,
-  IostatIntegerInputOverflow,
-  IostatRealInputOverflow,
-  IostatOpenAlreadyConnected,
-  IostatCannotReposition,
-  IostatBadWaitId,
-  IostatTooManyAsyncOps,
-  IostatBadBackspaceUnit,
-  IostatBadUnitNumber,
-  IostatBadFlushUnit,
-  IostatBadOpOnChildUnit,
-  IostatBadNewUnit,
-  IostatBadListDirectedInputSeparator,
-  IostatNonExternalDefinedUnformattedIo,
-};
+namespace Fortran::runtime::io {
 
 RT_API_ATTRS const char *IostatErrorString(int);
 

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 41b739560aea83..292b0783974369 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -56,7 +56,7 @@
 #include "flang/Optimizer/Support/InternalNames.h"
 #include "flang/Optimizer/Transforms/Passes.h"
 #include "flang/Parser/parse-tree.h"
-#include "flang/Runtime/iostat.h"
+#include "flang/Runtime/iostat-consts.h"
 #include "flang/Semantics/runtime-type-info.h"
 #include "flang/Semantics/symbol.h"
 #include "flang/Semantics/tools.h"

diff  --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 197e526973b4d3..ff122c21e37ade 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -39,7 +39,7 @@
 #include "flang/Optimizer/Support/FatalError.h"
 #include "flang/Optimizer/Support/InternalNames.h"
 #include "flang/Optimizer/Support/Utils.h"
-#include "flang/Runtime/allocator-registry.h"
+#include "flang/Runtime/allocator-registry-consts.h"
 #include "flang/Semantics/runtime-type-info.h"
 #include "flang/Semantics/tools.h"
 #include "llvm/Support/CommandLine.h"

diff  --git a/flang/lib/Lower/IO.cpp b/flang/lib/Lower/IO.cpp
index 1894b0cfd1bec2..6a918d844c12e4 100644
--- a/flang/lib/Lower/IO.cpp
+++ b/flang/lib/Lower/IO.cpp
@@ -33,7 +33,7 @@
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
 #include "flang/Parser/parse-tree.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 #include "flang/Semantics/runtime-type-info.h"
 #include "flang/Semantics/tools.h"
 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"

diff  --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 2758da48bceca4..547cebefd2df47 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -41,7 +41,7 @@
 #include "flang/Optimizer/Support/FatalError.h"
 #include "flang/Optimizer/Support/Utils.h"
 #include "flang/Runtime/entry-names.h"
-#include "flang/Runtime/iostat.h"
+#include "flang/Runtime/iostat-consts.h"
 #include "mlir/Dialect/Complex/IR/Complex.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/Dialect/Math/IR/Math.h"

diff  --git a/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp b/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
index c786bef5cb1c4c..0d56cd2edc99b5 100644
--- a/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
@@ -9,7 +9,7 @@
 #include "flang/Optimizer/Builder/Runtime/ArrayConstructor.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
-#include "flang/Runtime/array-constructor.h"
+#include "flang/Runtime/array-constructor-consts.h"
 
 using namespace Fortran::runtime;
 
@@ -25,12 +25,13 @@ mlir::Value fir::runtime::genInitArrayConstructorVector(
     mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value toBox,
     mlir::Value useValueLengthParameters) {
   // Allocate storage for the runtime cookie for the array constructor vector.
-  // Use the "host" size and alignment, but double them to be safe regardless of
-  // the target. The "cookieSize" argument is used to validate this wild
-  // assumption until runtime interfaces are improved.
+  // Use pessimistic values for size and alignment that are valid for all
+  // supported targets. Whether the actual ArrayConstructorVector object fits
+  // into the available MaxArrayConstructorVectorSizeInBytes is verified when
+  // building clang-rt.
   std::size_t arrayVectorStructBitSize =
-      2 * sizeof(Fortran::runtime::ArrayConstructorVector) * 8;
-  std::size_t alignLike = alignof(Fortran::runtime::ArrayConstructorVector) * 8;
+      MaxArrayConstructorVectorSizeInBytes * 8;
+  std::size_t alignLike = MaxArrayConstructorVectorAlignInBytes * 8;
   fir::SequenceType::Extent numElem =
       (arrayVectorStructBitSize + alignLike - 1) / alignLike;
   mlir::Type intType = builder.getIntegerType(alignLike);
@@ -43,14 +44,12 @@ mlir::Value fir::runtime::genInitArrayConstructorVector(
           loc, builder);
   mlir::FunctionType funcType = func.getFunctionType();
   cookie = builder.createConvert(loc, funcType.getInput(0), cookie);
-  mlir::Value cookieSize = builder.createIntegerConstant(
-      loc, funcType.getInput(3), numElem * alignLike / 8);
   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
   mlir::Value sourceLine =
-      fir::factory::locationToLineNo(builder, loc, funcType.getInput(5));
+      fir::factory::locationToLineNo(builder, loc, funcType.getInput(4));
   auto args = fir::runtime::createArguments(builder, loc, funcType, cookie,
                                             toBox, useValueLengthParameters,
-                                            cookieSize, sourceFile, sourceLine);
+                                            sourceFile, sourceLine);
   builder.create<fir::CallOp>(loc, func, args);
   return cookie;
 }

diff  --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 2eeb182735094f..5345d64c330f06 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -23,8 +23,8 @@
 #include "flang/Optimizer/Support/InternalNames.h"
 #include "flang/Optimizer/Support/TypeCode.h"
 #include "flang/Optimizer/Support/Utils.h"
-#include "flang/Runtime/allocator-registry.h"
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/allocator-registry-consts.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Semantics/runtime-type-info.h"
 #include "mlir/Conversion/ArithCommon/AttrToLLVMConverter.h"
 #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h"
@@ -1322,16 +1322,12 @@ struct EmboxCommonConversion : public fir::FIROpConversion<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) {

diff  --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
index 028633813a91b6..94640fa30baa54 100644
--- a/flang/lib/Semantics/compute-offsets.cpp
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -11,7 +11,7 @@
 #include "flang/Evaluate/fold.h"
 #include "flang/Evaluate/shape.h"
 #include "flang/Evaluate/type.h"
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 #include "flang/Semantics/scope.h"
 #include "flang/Semantics/semantics.h"
 #include "flang/Semantics/symbol.h"
@@ -339,8 +339,12 @@ auto ComputeOffsetsHelper::GetSizeAndAlignment(
     const auto *derived{evaluate::GetDerivedTypeSpec(dyType)};
     int lenParams{derived ? CountLenParameters(*derived) : 0};
     bool needAddendum{derived || (dyType && dyType->IsUnlimitedPolymorphic())};
-    std::size_t size{runtime::Descriptor::SizeInBytes(
+
+    // FIXME: Get descriptor size from targetCharacteristics instead
+    // overapproximation
+    std::size_t size{runtime::MaxDescriptorSizeInBytes(
         symbol.Rank(), needAddendum, lenParams)};
+
     return {size, targetCharacteristics.descriptorAlignment()};
   }
   if (IsProcedurePointer(symbol)) {

diff  --git a/flang/runtime/array-constructor.cpp b/flang/runtime/array-constructor.cpp
index 3d0e969188f259..0d677d7cc63aa9 100644
--- a/flang/runtime/array-constructor.cpp
+++ b/flang/runtime/array-constructor.cpp
@@ -92,13 +92,10 @@ extern "C" {
 RT_EXT_API_GROUP_BEGIN
 
 void RTDEF(InitArrayConstructorVector)(ArrayConstructorVector &vector,
-    Descriptor &to, bool useValueLengthParameters, int vectorClassSize,
-    const char *sourceFile, int sourceLine) {
+    Descriptor &to, bool useValueLengthParameters, const char *sourceFile,
+    int sourceLine) {
   Terminator terminator{vector.sourceFile, vector.sourceLine};
-  RUNTIME_CHECK(terminator,
-      to.rank() == 1 &&
-          sizeof(ArrayConstructorVector) <=
-              static_cast<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,

diff  --git a/flang/runtime/environment-default-list.h b/flang/runtime/environment-default-list.h
old mode 100755
new mode 100644

diff  --git a/flang/runtime/internal-unit.cpp b/flang/runtime/internal-unit.cpp
index f28700ee015815..f8f3877efb20ea 100644
--- a/flang/runtime/internal-unit.cpp
+++ b/flang/runtime/internal-unit.cpp
@@ -36,6 +36,8 @@ RT_API_ATTRS InternalDescriptorUnit<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;

diff  --git a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90
index e1e65fc48babad..727eff7613e48d 100644
--- a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90
@@ -17,12 +17,11 @@ subroutine test_loops()
 ! CHECK:           fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref<!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 @@ subroutine test_arrays(a)
 ! 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>>>

diff  --git a/flang/test/Lower/HLFIR/array-ctor-character.f90 b/flang/test/Lower/HLFIR/array-ctor-character.f90
index 881085b370ffef..7cbad5218f5881 100644
--- a/flang/test/Lower/HLFIR/array-ctor-character.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-character.f90
@@ -52,7 +52,7 @@ subroutine test_dynamic_length()
 ! CHECK:  %[[VAL_15:.*]] = arith.constant true
 ! CHECK:  %[[VAL_16:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.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(

diff  --git a/flang/test/Lower/HLFIR/array-ctor-derived.f90 b/flang/test/Lower/HLFIR/array-ctor-derived.f90
index 111225462a4bbe..22f7fbd72cb59f 100644
--- a/flang/test/Lower/HLFIR/array-ctor-derived.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-derived.f90
@@ -28,7 +28,7 @@ subroutine test_simple(s1, s2)
 ! CHECK:  %[[VAL_11:.*]] = arith.constant false
 ! CHECK:  %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.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 @@ subroutine test_with_polymorphic(s1, s2)
 ! 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

diff  --git a/flang/test/Lower/HLFIR/structure-constructor.f90 b/flang/test/Lower/HLFIR/structure-constructor.f90
index 41d08c14f5fa98..ed9ee5d0ac363b 100644
--- a/flang/test/Lower/HLFIR/structure-constructor.f90
+++ b/flang/test/Lower/HLFIR/structure-constructor.f90
@@ -273,12 +273,11 @@ end subroutine test6
 ! CHECK:           fir.store %[[VAL_49]] to %[[VAL_4]] : !fir.ref<!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]*}}>>

diff  --git a/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp
index 1db43cacc90f07..f618e72d7b7f3c 100644
--- a/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp
+++ b/flang/unittests/Optimizer/Builder/Runtime/AllocatableTest.cpp
@@ -9,7 +9,7 @@
 #include "flang/Optimizer/Builder/Runtime/Allocatable.h"
 #include "RuntimeCallTestBase.h"
 #include "gtest/gtest.h"
-#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/descriptor-consts.h"
 
 using namespace Fortran::runtime;
 

diff  --git a/flang/unittests/Runtime/ArrayConstructor.cpp b/flang/unittests/Runtime/ArrayConstructor.cpp
index 9d78da79623613..62e3b780a27e72 100644
--- a/flang/unittests/Runtime/ArrayConstructor.cpp
+++ b/flang/unittests/Runtime/ArrayConstructor.cpp
@@ -43,8 +43,7 @@ TEST(ArrayConstructor, Basic) {
   result.GetDimension(0).SetBounds(1, 0);
 
   RTNAME(InitArrayConstructorVector)
-  (*acVector, result, /*useValueLengthParameters=*/false,
-      /*vectorClassSize=*/sizeof(ArrayConstructorVector));
+  (*acVector, result, /*useValueLengthParameters=*/false);
   for (std::int32_t i{0}; i <= 99; ++i) {
     RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i);
     RTNAME(PushArrayConstructorValue)(*acVector, *x);
@@ -71,8 +70,7 @@ TEST(ArrayConstructor, Basic) {
   // and is allocated when the first value is pushed.
   result.GetDimension(0).SetBounds(1, 1234);
   RTNAME(InitArrayConstructorVector)
-  (*acVector, result, /*useValueLengthParameters=*/false,
-      /*vectorClassSize=*/sizeof(ArrayConstructorVector));
+  (*acVector, result, /*useValueLengthParameters=*/false);
   EXPECT_EQ(0, acVector->actualAllocationSize);
   std::int32_t i{42};
   RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i);
@@ -109,8 +107,7 @@ TEST(ArrayConstructor, Character) {
   static constexpr std::size_t expectedElements{10 * (1 + 4 + 2 * 3)};
   result.GetDimension(0).SetBounds(1, 0);
   RTNAME(InitArrayConstructorVector)
-  (*acVector, result, /*useValueLengthParameters=*/true,
-      /*vectorClassSize=*/sizeof(ArrayConstructorVector));
+  (*acVector, result, /*useValueLengthParameters=*/true);
   for (std::int32_t i{1}; i <= 10; ++i) {
     RTNAME(PushArrayConstructorValue)(*acVector, *c);
     RTNAME(PushArrayConstructorValue)(*acVector, *x);
@@ -151,8 +148,7 @@ TEST(ArrayConstructor, CharacterRuntimeCheck) {
 
   result.GetDimension(0).SetBounds(1, 0);
   RTNAME(InitArrayConstructorVector)
-  (*acVector, result, /*useValueLengthParameters=*/true,
-      /*vectorClassSize=*/sizeof(ArrayConstructorVector));
+  (*acVector, result, /*useValueLengthParameters=*/true);
   RTNAME(PushArrayConstructorValue)(*acVector, *c2);
   ASSERT_DEATH(RTNAME(PushArrayConstructorValue)(*acVector, *c3),
       "Array constructor: mismatched character lengths");

diff  --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp
index 13327964e12a48..b9407b5e7a591e 100644
--- a/flang/unittests/Runtime/ExternalIOTest.cpp
+++ b/flang/unittests/Runtime/ExternalIOTest.cpp
@@ -13,7 +13,7 @@
 #include "CrashHandlerFixture.h"
 #include "gtest/gtest.h"
 #include "flang/Runtime/descriptor.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 #include "flang/Runtime/main.h"
 #include "flang/Runtime/stop.h"
 #include "llvm/Support/raw_ostream.h"

diff  --git a/flang/unittests/Runtime/ListInputTest.cpp b/flang/unittests/Runtime/ListInputTest.cpp
index a4eba5283add68..38c758b7ef9662 100644
--- a/flang/unittests/Runtime/ListInputTest.cpp
+++ b/flang/unittests/Runtime/ListInputTest.cpp
@@ -9,7 +9,7 @@
 #include "CrashHandlerFixture.h"
 #include "../../runtime/io-error.h"
 #include "flang/Runtime/descriptor.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 
 using namespace Fortran::runtime;
 using namespace Fortran::runtime::io;

diff  --git a/flang/unittests/Runtime/LogicalFormatTest.cpp b/flang/unittests/Runtime/LogicalFormatTest.cpp
index a2c19d1e1ca948..c4fbfc81f06a43 100644
--- a/flang/unittests/Runtime/LogicalFormatTest.cpp
+++ b/flang/unittests/Runtime/LogicalFormatTest.cpp
@@ -8,7 +8,7 @@
 
 #include "CrashHandlerFixture.h"
 #include "flang/Runtime/descriptor.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 #include <algorithm>
 #include <array>
 #include <cstring>

diff  --git a/flang/unittests/Runtime/Namelist.cpp b/flang/unittests/Runtime/Namelist.cpp
index 9037fa15a97cb3..0a28f3590b86ed 100644
--- a/flang/unittests/Runtime/Namelist.cpp
+++ b/flang/unittests/Runtime/Namelist.cpp
@@ -10,7 +10,7 @@
 #include "CrashHandlerFixture.h"
 #include "tools.h"
 #include "flang/Runtime/descriptor.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 #include <algorithm>
 #include <cinttypes>
 #include <complex>

diff  --git a/flang/unittests/Runtime/NumericalFormatTest.cpp b/flang/unittests/Runtime/NumericalFormatTest.cpp
index f0055153203508..274498b8e86951 100644
--- a/flang/unittests/Runtime/NumericalFormatTest.cpp
+++ b/flang/unittests/Runtime/NumericalFormatTest.cpp
@@ -8,7 +8,7 @@
 
 #include "CrashHandlerFixture.h"
 #include "flang/Runtime/descriptor.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 #include <algorithm>
 #include <array>
 #include <cstring>

diff  --git a/flang/unittests/Runtime/RuntimeCrashTest.cpp b/flang/unittests/Runtime/RuntimeCrashTest.cpp
index a649051fdca0c5..72a0b290cf8643 100644
--- a/flang/unittests/Runtime/RuntimeCrashTest.cpp
+++ b/flang/unittests/Runtime/RuntimeCrashTest.cpp
@@ -13,7 +13,7 @@
 #include "CrashHandlerFixture.h"
 #include "tools.h"
 #include "../../runtime/terminator.h"
-#include "flang/Runtime/io-api.h"
+#include "flang/Runtime/io-api-consts.h"
 #include "flang/Runtime/transformational.h"
 #include <gtest/gtest.h>
 


        


More information about the flang-commits mailing list