1 //===-- HlfirIntrinsics.h -- lowering to HLFIR intrinsic ops ----*- C++ -*-===// 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 /// Implements lowering of transformational intrinsics to HLFIR intrinsic 14 /// operations 15 /// 16 //===----------------------------------------------------------------------===// 17 18 #ifndef FORTRAN_LOWER_HLFIRINTRINSICS_H 19 #define FORTRAN_LOWER_HLFIRINTRINSICS_H 20 21 #include "flang/Optimizer/Builder/HLFIRTools.h" 22 #include "flang/Optimizer/Builder/Todo.h" 23 #include "flang/Optimizer/HLFIR/HLFIROps.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include <cassert> 26 #include <optional> 27 #include <string> 28 29 namespace mlir { 30 class Location; 31 class Type; 32 class Value; 33 class ValueRange; 34 } // namespace mlir 35 36 namespace fir { 37 class FirOpBuilder; 38 struct IntrinsicArgumentLoweringRules; 39 } // namespace fir 40 41 namespace Fortran::lower { 42 43 /// This structure holds the initial lowered value of an actual argument that 44 /// was lowered regardless of the interface, and it holds whether or not it 45 /// may be absent at runtime and the dummy is optional. 46 struct PreparedActualArgument { 47 PreparedActualArgumentPreparedActualArgument48 PreparedActualArgument(hlfir::Entity actual, 49 std::optional<mlir::Value> isPresent) 50 : actual{actual}, isPresent{isPresent} {} PreparedActualArgumentPreparedActualArgument51 PreparedActualArgument(hlfir::ElementalAddrOp vectorSubscriptedActual) 52 : actual{vectorSubscriptedActual}, isPresent{std::nullopt} {} setElementalIndicesPreparedActualArgument53 void setElementalIndices(mlir::ValueRange &indices) { 54 oneBasedElementalIndices = &indices; 55 } 56 57 /// Get the prepared actual. If this is an array argument in an elemental 58 /// call, the current element value will be returned. 59 hlfir::Entity getActual(mlir::Location loc, fir::FirOpBuilder &builder) const; 60 derefPointersAndAllocatablesPreparedActualArgument61 void derefPointersAndAllocatables(mlir::Location loc, 62 fir::FirOpBuilder &builder) { 63 if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) 64 actual = hlfir::derefPointersAndAllocatables(loc, builder, *actualEntity); 65 } 66 loadTrivialScalarPreparedActualArgument67 void loadTrivialScalar(mlir::Location loc, fir::FirOpBuilder &builder) { 68 if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) 69 actual = hlfir::loadTrivialScalar(loc, builder, *actualEntity); 70 } 71 72 /// Ensure an array expression argument is fully evaluated in memory before 73 /// the call. Useful for impure elemental calls. associateIfArrayExprPreparedActualArgument74 hlfir::AssociateOp associateIfArrayExpr(mlir::Location loc, 75 fir::FirOpBuilder &builder) { 76 if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) { 77 if (!actualEntity->isVariable() && actualEntity->isArray()) { 78 mlir::Type storageType = actualEntity->getType(); 79 hlfir::AssociateOp associate = hlfir::genAssociateExpr( 80 loc, builder, *actualEntity, storageType, "adapt.impure_arg_eval"); 81 actual = hlfir::Entity{associate}; 82 return associate; 83 } 84 } 85 return {}; 86 } 87 isArrayPreparedActualArgument88 bool isArray() const { 89 return std::holds_alternative<hlfir::ElementalAddrOp>(actual) || 90 std::get<hlfir::Entity>(actual).isArray(); 91 } 92 genShapePreparedActualArgument93 mlir::Value genShape(mlir::Location loc, fir::FirOpBuilder &builder) { 94 if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) 95 return hlfir::genShape(loc, builder, *actualEntity); 96 return std::get<hlfir::ElementalAddrOp>(actual).getShape(); 97 } 98 genCharLengthPreparedActualArgument99 mlir::Value genCharLength(mlir::Location loc, fir::FirOpBuilder &builder) { 100 if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) 101 return hlfir::genCharLength(loc, builder, *actualEntity); 102 auto typeParams = std::get<hlfir::ElementalAddrOp>(actual).getTypeparams(); 103 assert(typeParams.size() == 1 && 104 "failed to retrieve vector subscripted character length"); 105 return typeParams[0]; 106 } 107 108 /// When the argument is polymorphic, get mold value with the same dynamic 109 /// type. getPolymorphicMoldPreparedActualArgument110 mlir::Value getPolymorphicMold(mlir::Location loc) const { 111 if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) 112 return *actualEntity; 113 TODO(loc, "polymorphic vector subscripts"); 114 } 115 handleDynamicOptionalPreparedActualArgument116 bool handleDynamicOptional() const { return isPresent.has_value(); } getIsPresentPreparedActualArgument117 mlir::Value getIsPresent() const { 118 assert(handleDynamicOptional() && "not a dynamic optional"); 119 return *isPresent; 120 } 121 resetOptionalAspectPreparedActualArgument122 void resetOptionalAspect() { isPresent = std::nullopt; } 123 124 private: 125 std::variant<hlfir::Entity, hlfir::ElementalAddrOp> actual; 126 mlir::ValueRange *oneBasedElementalIndices{nullptr}; 127 // When the actual may be dynamically optional, "isPresent" 128 // holds a boolean value indicating the presence of the 129 // actual argument at runtime. 130 std::optional<mlir::Value> isPresent; 131 }; 132 133 /// Vector of pre-lowered actual arguments. nullopt if the actual is 134 /// "statically" absent (if it was not syntactically provided). 135 using PreparedActualArguments = 136 llvm::SmallVector<std::optional<PreparedActualArgument>>; 137 138 std::optional<hlfir::EntityWithAttributes> lowerHlfirIntrinsic( 139 fir::FirOpBuilder &builder, mlir::Location loc, const std::string &name, 140 const Fortran::lower::PreparedActualArguments &loweredActuals, 141 const fir::IntrinsicArgumentLoweringRules *argLowering, 142 mlir::Type stmtResultType); 143 144 } // namespace Fortran::lower 145 #endif // FORTRAN_LOWER_HLFIRINTRINSICS_H 146