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