xref: /llvm-project/flang/include/flang/Lower/HlfirIntrinsics.h (revision 8c2ed5ccc26cbe1c5d146231ac4ce628e403b590)
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