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 "llvm/ADT/StringRef.h" 18 19 namespace mlir { 20 class Value; 21 class ValueRange; 22 class Type; 23 class Location; 24 } // namespace mlir 25 26 namespace fir { 27 class FirOpBuilder; 28 class MutableBoxValue; 29 class ExtendedValue; 30 } // namespace fir 31 32 namespace fir::factory { 33 34 /// Create a fir.box of type \p boxType that can be used to initialize an 35 /// allocatable variable. Initialization of such variable has to be done at the 36 /// beginning of the variable lifetime by storing the created box in the memory 37 /// for the variable box. 38 /// \p nonDeferredParams must provide the non deferred LEN parameters so that 39 /// they can already be placed in the unallocated box (inquiries about these 40 /// parameters are legal even in unallocated state). 41 mlir::Value createUnallocatedBox(fir::FirOpBuilder &builder, mlir::Location loc, 42 mlir::Type boxType, 43 mlir::ValueRange nonDeferredParams); 44 45 /// Create a MutableBoxValue for a temporary allocatable. 46 /// The created MutableBoxValue wraps a fir.ref<fir.box<fir.heap<type>>> and is 47 /// initialized to unallocated/diassociated status. An optional name can be 48 /// given to the created !fir.ref<fir.box>. 49 fir::MutableBoxValue createTempMutableBox(fir::FirOpBuilder &builder, 50 mlir::Location loc, mlir::Type type, 51 llvm::StringRef name = {}); 52 53 /// Update a MutableBoxValue to describe entity \p source (that must be in 54 /// memory). If \lbounds is not empty, it is used to defined the MutableBoxValue 55 /// lower bounds, otherwise, the lower bounds from \p source are used. 56 void associateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc, 57 const fir::MutableBoxValue &box, 58 const fir::ExtendedValue &source, 59 mlir::ValueRange lbounds); 60 61 /// Update a MutableBoxValue to describe entity \p source (that must be in 62 /// memory) with a new array layout given by \p lbounds and \p ubounds. 63 /// \p source must be known to be contiguous at compile time, or it must have 64 /// rank 1 (constraint from Fortran 2018 standard 10.2.2.3 point 9). 65 void associateMutableBoxWithRemap(fir::FirOpBuilder &builder, 66 mlir::Location loc, 67 const fir::MutableBoxValue &box, 68 const fir::ExtendedValue &source, 69 mlir::ValueRange lbounds, 70 mlir::ValueRange ubounds); 71 72 /// Set the association status of a MutableBoxValue to 73 /// disassociated/unallocated. Nothing is done with the entity that was 74 /// previously associated/allocated. The function generates code that sets the 75 /// address field of the MutableBoxValue to zero. 76 void disassociateMutableBox(fir::FirOpBuilder &builder, mlir::Location loc, 77 const fir::MutableBoxValue &box); 78 79 /// Generate code to conditionally reallocate a MutableBoxValue with a new 80 /// shape, lower bounds, and LEN parameters if it is unallocated or if its 81 /// current shape or deferred LEN parameters do not match the provided ones. 82 /// Lower bounds are only used if the entity needs to be allocated, otherwise, 83 /// the MutableBoxValue will keep its current lower bounds. 84 /// If the MutableBoxValue is an array, the provided shape can be empty, in 85 /// which case the MutableBoxValue must already be allocated at runtime and its 86 /// shape and lower bounds will be kept. If \p shape is empty, only a LEN 87 /// parameter mismatch can trigger a reallocation. See Fortran 10.2.1.3 point 3 88 /// that this function is implementing for more details. The polymorphic 89 /// requirements are not yet covered by this function. 90 struct MutableBoxReallocation { 91 fir::ExtendedValue newValue; 92 mlir::Value oldAddress; 93 mlir::Value wasReallocated; 94 mlir::Value oldAddressWasAllocated; 95 }; 96 97 /// Type of a callback invoked on every storage pointer produced 98 /// in different branches by genReallocIfNeeded(). The argument 99 /// is an ExtendedValue for the storage pointer. 100 /// For example, when genReallocIfNeeded() is used for a LHS allocatable 101 /// array in an assignment, the callback performs the actual assignment 102 /// via the given storage pointer, so we end up generating array_updates and 103 /// array_merge_stores in each branch. 104 using ReallocStorageHandlerFunc = std::function<void(fir::ExtendedValue)>; 105 106 MutableBoxReallocation 107 genReallocIfNeeded(fir::FirOpBuilder &builder, mlir::Location loc, 108 const fir::MutableBoxValue &box, mlir::ValueRange shape, 109 mlir::ValueRange lenParams, 110 ReallocStorageHandlerFunc storageHandler = {}); 111 112 void finalizeRealloc(fir::FirOpBuilder &builder, mlir::Location loc, 113 const fir::MutableBoxValue &box, mlir::ValueRange lbounds, 114 bool takeLboundsIfRealloc, 115 const MutableBoxReallocation &realloc); 116 117 /// Finalize a mutable box if it is allocated or associated. This includes both 118 /// calling the finalizer, if any, and deallocating the storage. 119 void genFinalization(fir::FirOpBuilder &builder, mlir::Location loc, 120 const fir::MutableBoxValue &box); 121 122 void genInlinedAllocation(fir::FirOpBuilder &builder, mlir::Location loc, 123 const fir::MutableBoxValue &box, 124 mlir::ValueRange lbounds, mlir::ValueRange extents, 125 mlir::ValueRange lenParams, 126 llvm::StringRef allocName); 127 128 void genInlinedDeallocate(fir::FirOpBuilder &builder, mlir::Location loc, 129 const fir::MutableBoxValue &box); 130 131 /// When the MutableBoxValue was passed as a fir.ref<fir.box> to a call that may 132 /// have modified it, update the MutableBoxValue according to the 133 /// fir.ref<fir.box> value. 134 void syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, mlir::Location loc, 135 const fir::MutableBoxValue &box); 136 137 /// Read all mutable properties into a normal symbol box. 138 /// It is OK to call this on unassociated/unallocated boxes but any use of the 139 /// resulting values will be undefined (only the base address will be guaranteed 140 /// to be null). 141 fir::ExtendedValue genMutableBoxRead(fir::FirOpBuilder &builder, 142 mlir::Location loc, 143 const fir::MutableBoxValue &box, 144 bool mayBePolymorphic = true); 145 146 /// Returns the fir.ref<fir.box<T>> of a MutableBoxValue filled with the current 147 /// association / allocation properties. If the fir.ref<fir.box> already exists 148 /// and is-up to date, this is a no-op, otherwise, code will be generated to 149 /// fill it. 150 mlir::Value getMutableIRBox(fir::FirOpBuilder &builder, mlir::Location loc, 151 const fir::MutableBoxValue &box); 152 153 /// Generate allocation or association status test and returns the resulting 154 /// i1. This is testing this for a valid/non-null base address value. 155 mlir::Value genIsAllocatedOrAssociatedTest(fir::FirOpBuilder &builder, 156 mlir::Location loc, 157 const fir::MutableBoxValue &box); 158 159 } // namespace fir::factory 160 161 #endif // FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H 162