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