1 //===-- MutableBox.h -- MutableBox utilities -----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H 14 #define FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H 15 16 #include "flang/Optimizer/Builder/BoxValue.h" 17 #include "flang/Runtime/allocator-registry-consts.h" 18 #include "llvm/ADT/StringRef.h" 19 20 namespace mlir { 21 class Value; 22 class ValueRange; 23 class Type; 24 class Location; 25 } // namespace mlir 26 27 namespace fir { 28 class FirOpBuilder; 29 class MutableBoxValue; 30 class ExtendedValue; 31 } // namespace fir 32 33 namespace fir::factory { 34 35 /// Create a fir.box of type \p boxType that can be used to initialize an 36 /// allocatable variable. Initialization of such variable has to be done at the 37 /// beginning of the variable lifetime by storing the created box in the memory 38 /// for the variable box. 39 /// \p nonDeferredParams must provide the non deferred LEN parameters so that 40 /// they can already be placed in the unallocated box (inquiries about these 41 /// parameters are legal even in unallocated state). 42 /// \p typeSourceBox provides the dynamic type information when the box is 43 /// created for a polymorphic temporary. 44 mlir::Value createUnallocatedBox(fir::FirOpBuilder &builder, mlir::Location loc, 45 mlir::Type boxType, 46 mlir::ValueRange nonDeferredParams, 47 mlir::Value typeSourceBox = {}, 48 unsigned allocator = kDefaultAllocator); 49 50 /// Create a MutableBoxValue for a temporary allocatable. 51 /// The created MutableBoxValue wraps a fir.ref<fir.box<fir.heap<type>>> and is 52 /// initialized to unallocated/diassociated status. An optional name can be 53 /// given to the created !fir.ref<fir.box>. 54 fir::MutableBoxValue createTempMutableBox(fir::FirOpBuilder &builder, 55 mlir::Location loc, mlir::Type type, 56 llvm::StringRef name = {}, 57 mlir::Value sourceBox = {}, 58 bool isPolymorphic = false); 59 60 /// Update a MutableBoxValue to describe entity \p source (that must be in 61 /// memory). If \lbounds is not empty, it is used to defined the MutableBoxValue 62 /// lower bounds, otherwise, the lower bounds from \p source are used. 63 void associateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc, 64 const fir::MutableBoxValue &box, 65 const fir::ExtendedValue &source, 66 mlir::ValueRange lbounds); 67 68 /// Update a MutableBoxValue to describe entity \p source (that must be in 69 /// memory) with a new array layout given by \p lbounds and \p ubounds. 70 /// \p source must be known to be contiguous at compile time, or it must have 71 /// rank 1 (constraint from Fortran 2018 standard 10.2.2.3 point 9). 72 void associateMutableBoxWithRemap(fir::FirOpBuilder &builder, 73 mlir::Location loc, 74 const fir::MutableBoxValue &box, 75 const fir::ExtendedValue &source, 76 mlir::ValueRange lbounds, 77 mlir::ValueRange ubounds); 78 79 /// Set the association status of a MutableBoxValue to 80 /// disassociated/unallocated. Nothing is done with the entity that was 81 /// previously associated/allocated. The function generates code that sets the 82 /// address field of the MutableBoxValue to zero. 83 void disassociateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc, 84 const fir::MutableBoxValue &box, 85 bool polymorphicSetType = true, 86 unsigned allocator = kDefaultAllocator); 87 88 /// Generate code to conditionally reallocate a MutableBoxValue with a new 89 /// shape, lower bounds, and LEN parameters if it is unallocated or if its 90 /// current shape or deferred LEN parameters do not match the provided ones. 91 /// Lower bounds are only used if the entity needs to be allocated, otherwise, 92 /// the MutableBoxValue will keep its current lower bounds. 93 /// If the MutableBoxValue is an array, the provided shape can be empty, in 94 /// which case the MutableBoxValue must already be allocated at runtime and its 95 /// shape and lower bounds will be kept. If \p shape is empty, only a LEN 96 /// parameter mismatch can trigger a reallocation. See Fortran 10.2.1.3 point 3 97 /// that this function is implementing for more details. The polymorphic 98 /// requirements are not yet covered by this function. 99 struct MutableBoxReallocation { 100 fir::ExtendedValue newValue; 101 mlir::Value oldAddress; 102 mlir::Value wasReallocated; 103 mlir::Value oldAddressWasAllocated; 104 }; 105 106 /// Type of a callback invoked on every storage pointer produced 107 /// in different branches by genReallocIfNeeded(). The argument 108 /// is an ExtendedValue for the storage pointer. 109 /// For example, when genReallocIfNeeded() is used for a LHS allocatable 110 /// array in an assignment, the callback performs the actual assignment 111 /// via the given storage pointer, so we end up generating array_updates and 112 /// array_merge_stores in each branch. 113 using ReallocStorageHandlerFunc = std::function<void(fir::ExtendedValue)>; 114 115 MutableBoxReallocation 116 genReallocIfNeeded(fir::FirOpBuilder &builder, mlir::Location loc, 117 const fir::MutableBoxValue &box, mlir::ValueRange shape, 118 mlir::ValueRange lenParams, 119 ReallocStorageHandlerFunc storageHandler = {}); 120 121 void finalizeRealloc(fir::FirOpBuilder &builder, mlir::Location loc, 122 const fir::MutableBoxValue &box, mlir::ValueRange lbounds, 123 bool takeLboundsIfRealloc, 124 const MutableBoxReallocation &realloc); 125 126 /// Deallocate a mutable box with fir.freemem if it is allocated or associated. 127 /// This only deallocates the storage and does not call finalization, the 128 /// mutable box is not nullified. 129 void genFreememIfAllocated(fir::FirOpBuilder &builder, mlir::Location loc, 130 const fir::MutableBoxValue &box); 131 132 void genInlinedAllocation(fir::FirOpBuilder &builder, mlir::Location loc, 133 const fir::MutableBoxValue &box, 134 mlir::ValueRange lbounds, mlir::ValueRange extents, 135 mlir::ValueRange lenParams, llvm::StringRef allocName, 136 bool mustBeHeap = false); 137 138 /// Deallocate an mutable box storage with fir.freemem without calling any 139 /// final procedures. The mutable box is not nullified. 140 mlir::Value genFreemem(fir::FirOpBuilder &builder, mlir::Location loc, 141 const fir::MutableBoxValue &box); 142 143 /// When the MutableBoxValue was passed as a fir.ref<fir.box> to a call that may 144 /// have modified it, update the MutableBoxValue according to the 145 /// fir.ref<fir.box> value. 146 void syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, mlir::Location loc, 147 const fir::MutableBoxValue &box); 148 149 /// Read all mutable properties into a normal symbol box. 150 /// It is OK to call this on unassociated/unallocated boxes but any use of the 151 /// resulting values will be undefined (only the base address will be guaranteed 152 /// to be null). 153 fir::ExtendedValue genMutableBoxRead(fir::FirOpBuilder &builder, 154 mlir::Location loc, 155 const fir::MutableBoxValue &box, 156 bool mayBePolymorphic = true, 157 bool preserveLowerBounds = true); 158 159 /// Returns the fir.ref<fir.box<T>> of a MutableBoxValue filled with the current 160 /// association / allocation properties. If the fir.ref<fir.box> already exists 161 /// and is-up to date, this is a no-op, otherwise, code will be generated to 162 /// fill it. 163 mlir::Value getMutableIRBox(fir::FirOpBuilder &builder, mlir::Location loc, 164 const fir::MutableBoxValue &box); 165 166 /// Generate allocation or association status test and returns the resulting 167 /// i1. This is testing this for a valid/non-null base address value. 168 mlir::Value genIsAllocatedOrAssociatedTest(fir::FirOpBuilder &builder, 169 mlir::Location loc, 170 const fir::MutableBoxValue &box); 171 172 /// Generate allocation or association status test and returns the resulting 173 /// i1. This is testing this for a valid/non-null base address value. 174 mlir::Value genIsNotAllocatedOrAssociatedTest(fir::FirOpBuilder &builder, 175 mlir::Location loc, 176 const fir::MutableBoxValue &box); 177 178 /// Generate an unallocated box of the given \p boxTy 179 /// and store it into a temporary storage. 180 /// Return address of the temporary storage. 181 mlir::Value genNullBoxStorage(fir::FirOpBuilder &builder, mlir::Location loc, 182 mlir::Type boxTy); 183 184 } // namespace fir::factory 185 186 #endif // FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H 187