1 //===-- ConvertExpr.cpp ---------------------------------------------------===//
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 #include "flang/Lower/ConvertExpr.h"
14 #include "flang/Evaluate/fold.h"
15 #include "flang/Evaluate/real.h"
16 #include "flang/Evaluate/traverse.h"
17 #include "flang/Lower/AbstractConverter.h"
18 #include "flang/Lower/Todo.h"
19 #include "flang/Semantics/expression.h"
20 #include "flang/Semantics/symbol.h"
21 #include "flang/Semantics/tools.h"
22 #include "flang/Semantics/type.h"
23 #include "mlir/Dialect/StandardOps/IR/Ops.h"
24 #include "llvm/Support/Debug.h"
25 
26 #define DEBUG_TYPE "flang-lower-expr"
27 
28 //===----------------------------------------------------------------------===//
29 // The composition and structure of Fortran::evaluate::Expr is defined in
30 // the various header files in include/flang/Evaluate. You are referred
31 // there for more information on these data structures. Generally speaking,
32 // these data structures are a strongly typed family of abstract data types
33 // that, composed as trees, describe the syntax of Fortran expressions.
34 //
35 // This part of the bridge can traverse these tree structures and lower them
36 // to the correct FIR representation in SSA form.
37 //===----------------------------------------------------------------------===//
38 
39 namespace {
40 
41 /// Lowering of Fortran::evaluate::Expr<T> expressions
42 class ScalarExprLowering {
43 public:
44   using ExtValue = fir::ExtendedValue;
45 
46   explicit ScalarExprLowering(mlir::Location loc,
47                               Fortran::lower::AbstractConverter &converter,
48                               Fortran::lower::SymMap &symMap)
49       : location{loc}, converter{converter},
50         builder{converter.getFirOpBuilder()}, symMap{symMap} {}
51 
52   mlir::Location getLoc() { return location; }
53 
54   /// Generate an integral constant of `value`
55   template <int KIND>
56   mlir::Value genIntegerConstant(mlir::MLIRContext *context,
57                                  std::int64_t value) {
58     mlir::Type type =
59         converter.genType(Fortran::common::TypeCategory::Integer, KIND);
60     return builder.createIntegerConstant(getLoc(), type, value);
61   }
62 
63   ExtValue genval(Fortran::semantics::SymbolRef sym) {
64     TODO(getLoc(), "genval SymbolRef");
65   }
66 
67   ExtValue genval(const Fortran::evaluate::BOZLiteralConstant &) {
68     TODO(getLoc(), "genval BOZ");
69   }
70 
71   /// Return indirection to function designated in ProcedureDesignator.
72   /// The type of the function indirection is not guaranteed to match the one
73   /// of the ProcedureDesignator due to Fortran implicit typing rules.
74   ExtValue genval(const Fortran::evaluate::ProcedureDesignator &proc) {
75     TODO(getLoc(), "genval ProcedureDesignator");
76   }
77 
78   ExtValue genval(const Fortran::evaluate::NullPointer &) {
79     TODO(getLoc(), "genval NullPointer");
80   }
81 
82   ExtValue genval(const Fortran::evaluate::StructureConstructor &ctor) {
83     TODO(getLoc(), "genval StructureConstructor");
84   }
85 
86   /// Lowering of an <i>ac-do-variable</i>, which is not a Symbol.
87   ExtValue genval(const Fortran::evaluate::ImpliedDoIndex &var) {
88     TODO(getLoc(), "genval ImpliedDoIndex");
89   }
90 
91   ExtValue genval(const Fortran::evaluate::DescriptorInquiry &desc) {
92     TODO(getLoc(), "genval DescriptorInquiry");
93   }
94 
95   ExtValue genval(const Fortran::evaluate::TypeParamInquiry &) {
96     TODO(getLoc(), "genval TypeParamInquiry");
97   }
98 
99   template <int KIND>
100   ExtValue genval(const Fortran::evaluate::ComplexComponent<KIND> &part) {
101     TODO(getLoc(), "genval ComplexComponent");
102   }
103 
104   template <int KIND>
105   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
106                       Fortran::common::TypeCategory::Integer, KIND>> &op) {
107     TODO(getLoc(), "genval Negate integer");
108   }
109 
110   template <int KIND>
111   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
112                       Fortran::common::TypeCategory::Real, KIND>> &op) {
113     TODO(getLoc(), "genval Negate real");
114   }
115   template <int KIND>
116   ExtValue genval(const Fortran::evaluate::Negate<Fortran::evaluate::Type<
117                       Fortran::common::TypeCategory::Complex, KIND>> &op) {
118     TODO(getLoc(), "genval Negate complex");
119   }
120 
121 #undef GENBIN
122 #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp)                           \
123   template <int KIND>                                                          \
124   ExtValue genval(const Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \
125                       Fortran::common::TypeCategory::GenBinTyCat, KIND>> &x) { \
126     TODO(getLoc(), "genval GenBinEvOp");                                       \
127   }
128 
129   GENBIN(Add, Integer, mlir::arith::AddIOp)
130   GENBIN(Add, Real, mlir::arith::AddFOp)
131   GENBIN(Add, Complex, fir::AddcOp)
132   GENBIN(Subtract, Integer, mlir::arith::SubIOp)
133   GENBIN(Subtract, Real, mlir::arith::SubFOp)
134   GENBIN(Subtract, Complex, fir::SubcOp)
135   GENBIN(Multiply, Integer, mlir::arith::MulIOp)
136   GENBIN(Multiply, Real, mlir::arith::MulFOp)
137   GENBIN(Multiply, Complex, fir::MulcOp)
138   GENBIN(Divide, Integer, mlir::arith::DivSIOp)
139   GENBIN(Divide, Real, mlir::arith::DivFOp)
140   GENBIN(Divide, Complex, fir::DivcOp)
141 
142   template <Fortran::common::TypeCategory TC, int KIND>
143   ExtValue genval(
144       const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &op) {
145     TODO(getLoc(), "genval Power");
146   }
147 
148   template <Fortran::common::TypeCategory TC, int KIND>
149   ExtValue genval(
150       const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>
151           &op) {
152     TODO(getLoc(), "genval RealToInt");
153   }
154 
155   template <int KIND>
156   ExtValue genval(const Fortran::evaluate::ComplexConstructor<KIND> &op) {
157     TODO(getLoc(), "genval ComplexConstructor");
158   }
159 
160   template <int KIND>
161   ExtValue genval(const Fortran::evaluate::Concat<KIND> &op) {
162     TODO(getLoc(), "genval Concat<KIND>");
163   }
164 
165   /// MIN and MAX operations
166   template <Fortran::common::TypeCategory TC, int KIND>
167   ExtValue
168   genval(const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>
169              &op) {
170     TODO(getLoc(), "genval Extremum<TC, KIND>");
171   }
172 
173   template <int KIND>
174   ExtValue genval(const Fortran::evaluate::SetLength<KIND> &x) {
175     TODO(getLoc(), "genval SetLength<KIND>");
176   }
177 
178   template <int KIND>
179   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
180                       Fortran::common::TypeCategory::Integer, KIND>> &op) {
181     TODO(getLoc(), "genval integer comparison");
182   }
183   template <int KIND>
184   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
185                       Fortran::common::TypeCategory::Real, KIND>> &op) {
186     TODO(getLoc(), "genval real comparison");
187   }
188   template <int KIND>
189   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
190                       Fortran::common::TypeCategory::Complex, KIND>> &op) {
191     TODO(getLoc(), "genval complex comparison");
192   }
193   template <int KIND>
194   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
195                       Fortran::common::TypeCategory::Character, KIND>> &op) {
196     TODO(getLoc(), "genval char comparison");
197   }
198 
199   ExtValue
200   genval(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) {
201     TODO(getLoc(), "genval comparison");
202   }
203 
204   template <Fortran::common::TypeCategory TC1, int KIND,
205             Fortran::common::TypeCategory TC2>
206   ExtValue
207   genval(const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>,
208                                           TC2> &convert) {
209     TODO(getLoc(), "genval convert<TC1, KIND, TC2>");
210   }
211 
212   template <typename A>
213   ExtValue genval(const Fortran::evaluate::Parentheses<A> &op) {
214     TODO(getLoc(), "genval parentheses<A>");
215   }
216 
217   template <int KIND>
218   ExtValue genval(const Fortran::evaluate::Not<KIND> &op) {
219     TODO(getLoc(), "genval Not<KIND>");
220   }
221 
222   template <int KIND>
223   ExtValue genval(const Fortran::evaluate::LogicalOperation<KIND> &op) {
224     TODO(getLoc(), "genval LogicalOperation<KIND>");
225   }
226 
227   /// Convert a scalar literal constant to IR.
228   template <Fortran::common::TypeCategory TC, int KIND>
229   ExtValue genScalarLit(
230       const Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>
231           &value) {
232     if constexpr (TC == Fortran::common::TypeCategory::Integer) {
233       return genIntegerConstant<KIND>(builder.getContext(), value.ToInt64());
234     } else if constexpr (TC == Fortran::common::TypeCategory::Logical) {
235       TODO(getLoc(), "genval bool constant");
236     } else if constexpr (TC == Fortran::common::TypeCategory::Real) {
237       TODO(getLoc(), "genval real constant");
238     } else if constexpr (TC == Fortran::common::TypeCategory::Complex) {
239       TODO(getLoc(), "genval complex constant");
240     } else /*constexpr*/ {
241       llvm_unreachable("unhandled constant");
242     }
243   }
244 
245   template <Fortran::common::TypeCategory TC, int KIND>
246   ExtValue
247   genval(const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>>
248              &con) {
249     if (con.Rank() > 0)
250       TODO(getLoc(), "genval array constant");
251     std::optional<Fortran::evaluate::Scalar<Fortran::evaluate::Type<TC, KIND>>>
252         opt = con.GetScalarValue();
253     assert(opt.has_value() && "constant has no value");
254     if constexpr (TC == Fortran::common::TypeCategory::Character) {
255       TODO(getLoc(), "genval char constant");
256     } else {
257       return genScalarLit<TC, KIND>(opt.value());
258     }
259   }
260 
261   fir::ExtendedValue genval(
262       const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &con) {
263     TODO(getLoc(), "genval constant derived");
264   }
265 
266   template <typename A>
267   ExtValue genval(const Fortran::evaluate::ArrayConstructor<A> &) {
268     TODO(getLoc(), "genval ArrayConstructor<A>");
269   }
270 
271   ExtValue genval(const Fortran::evaluate::ComplexPart &x) {
272     TODO(getLoc(), "genval ComplexPart");
273   }
274 
275   ExtValue genval(const Fortran::evaluate::Substring &ss) {
276     TODO(getLoc(), "genval Substring");
277   }
278 
279   ExtValue genval(const Fortran::evaluate::Subscript &subs) {
280     TODO(getLoc(), "genval Subscript");
281   }
282 
283   ExtValue genval(const Fortran::evaluate::DataRef &dref) {
284     TODO(getLoc(), "genval DataRef");
285   }
286 
287   ExtValue genval(const Fortran::evaluate::Component &cmpt) {
288     TODO(getLoc(), "genval Component");
289   }
290 
291   ExtValue genval(const Fortran::semantics::Bound &bound) {
292     TODO(getLoc(), "genval Bound");
293   }
294 
295   ExtValue genval(const Fortran::evaluate::ArrayRef &aref) {
296     TODO(getLoc(), "genval ArrayRef");
297   }
298 
299   ExtValue genval(const Fortran::evaluate::CoarrayRef &coref) {
300     TODO(getLoc(), "genval CoarrayRef");
301   }
302 
303   template <typename A>
304   ExtValue genval(const Fortran::evaluate::Designator<A> &des) {
305     TODO(getLoc(), "genval Designator<A>");
306   }
307 
308   template <typename A>
309   ExtValue genval(const Fortran::evaluate::FunctionRef<A> &funcRef) {
310     TODO(getLoc(), "genval FunctionRef<A>");
311   }
312 
313   ExtValue genval(const Fortran::evaluate::ProcedureRef &procRef) {
314     TODO(getLoc(), "genval ProcedureRef");
315   }
316 
317   template <typename A>
318   bool isScalar(const A &x) {
319     return x.Rank() == 0;
320   }
321 
322   template <typename A>
323   ExtValue genval(const Fortran::evaluate::Expr<A> &x) {
324     if (isScalar(x))
325       return std::visit([&](const auto &e) { return genval(e); }, x.u);
326     TODO(getLoc(), "genval Expr<A> arrays");
327   }
328 
329   template <int KIND>
330   ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type<
331                       Fortran::common::TypeCategory::Logical, KIND>> &exp) {
332     return std::visit([&](const auto &e) { return genval(e); }, exp.u);
333   }
334 
335 private:
336   mlir::Location location;
337   Fortran::lower::AbstractConverter &converter;
338   fir::FirOpBuilder &builder;
339   Fortran::lower::SymMap &symMap;
340 };
341 } // namespace
342 
343 fir::ExtendedValue Fortran::lower::createSomeExtendedExpression(
344     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
345     const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) {
346   LLVM_DEBUG(expr.AsFortran(llvm::dbgs() << "expr: ") << '\n');
347   return ScalarExprLowering{loc, converter, symMap}.genval(expr);
348 }
349