FLANG
RTBuilder.h
Go to the documentation of this file.
1//===-- RTBuilder.h ---------------------------------------------*- 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//===----------------------------------------------------------------------===//
15//===----------------------------------------------------------------------===//
16
17#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RTBUILDER_H
18#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RTBUILDER_H
19
20#include "flang/Common/uint128.h"
21#include "flang/Optimizer/Builder/FIRBuilder.h"
22#include "flang/Optimizer/Dialect/FIRDialect.h"
23#include "flang/Optimizer/Dialect/FIRType.h"
24#include "flang/Runtime/io-api.h"
25#include "flang/Runtime/reduce.h"
26#include "flang/Support/Fortran.h"
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/MLIRContext.h"
29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/SmallVector.h"
31#include <cstdint>
32#include <functional>
33
34#ifdef _MSC_VER
35// On Windows* OS GetCurrentProcessId returns DWORD aka uint32_t
36typedef std::uint32_t pid_t;
37#endif
38
39// Incomplete type indicating C99 complex ABI in interfaces. Beware, _Complex
40// and std::complex are layout compatible, but not compatible in all ABI call
41// interfaces (e.g. X86 32 bits). _Complex is not standard C++, so do not use
42// it here.
43struct c_float_complex_t;
44struct c_double_complex_t;
45
46namespace Fortran::runtime {
47class Descriptor;
48namespace typeInfo {
49class DerivedType;
50}
51} // namespace Fortran::runtime
52
53namespace fir::runtime {
54
55using TypeBuilderFunc = mlir::Type (*)(mlir::MLIRContext *);
56using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *);
57
58#define REDUCTION_REF_OPERATION_MODEL(T) \
59 template <> \
60 constexpr TypeBuilderFunc \
61 getModel<Fortran::runtime::ReferenceReductionOperation<T>>() { \
62 return [](mlir::MLIRContext *context) -> mlir::Type { \
63 TypeBuilderFunc f{getModel<T>()}; \
64 auto refTy = fir::ReferenceType::get(f(context)); \
65 return mlir::FunctionType::get(context, {refTy, refTy}, refTy); \
66 }; \
67 }
68
69#define REDUCTION_VALUE_OPERATION_MODEL(T) \
70 template <> \
71 constexpr TypeBuilderFunc \
72 getModel<Fortran::runtime::ValueReductionOperation<T>>() { \
73 return [](mlir::MLIRContext *context) -> mlir::Type { \
74 TypeBuilderFunc f{getModel<T>()}; \
75 auto refTy = fir::ReferenceType::get(f(context)); \
76 return mlir::FunctionType::get(context, {f(context), f(context)}, \
77 refTy); \
78 }; \
79 }
80
81#define REDUCTION_CHAR_OPERATION_MODEL(T) \
82 template <> \
83 constexpr TypeBuilderFunc \
84 getModel<Fortran::runtime::ReductionCharOperation<T>>() { \
85 return [](mlir::MLIRContext *context) -> mlir::Type { \
86 TypeBuilderFunc f{getModel<T>()}; \
87 auto voidTy = fir::LLVMPointerType::get( \
88 context, mlir::IntegerType::get(context, 8)); \
89 auto size_tTy = \
90 mlir::IntegerType::get(context, 8 * sizeof(std::size_t)); \
91 auto refTy = fir::ReferenceType::get(f(context)); \
92 return mlir::FunctionType::get( \
93 context, {refTy, size_tTy, refTy, refTy, size_tTy, size_tTy}, \
94 voidTy); \
95 }; \
96 }
97
98//===----------------------------------------------------------------------===//
99// Type builder models
100//===----------------------------------------------------------------------===//
101
102// TODO: all usages of sizeof in this file assume build == host == target.
103// This will need to be re-visited for cross compilation.
104
112template <typename T>
113static constexpr TypeBuilderFunc getModel();
114
115template <>
116constexpr TypeBuilderFunc getModel<unsigned int>() {
117 return [](mlir::MLIRContext *context) -> mlir::Type {
118 return mlir::IntegerType::get(context, 8 * sizeof(unsigned int));
119 };
120}
121template <>
122constexpr TypeBuilderFunc getModel<short int>() {
123 return [](mlir::MLIRContext *context) -> mlir::Type {
124 return mlir::IntegerType::get(context, 8 * sizeof(short int));
125 };
126}
127template <>
128constexpr TypeBuilderFunc getModel<short int *>() {
129 return [](mlir::MLIRContext *context) -> mlir::Type {
130 TypeBuilderFunc f{getModel<short int>()};
131 return fir::ReferenceType::get(f(context));
132 };
133}
134template <>
135constexpr TypeBuilderFunc getModel<const short int *>() {
136 return getModel<short int *>();
137}
138template <>
139constexpr TypeBuilderFunc getModel<int>() {
140 return [](mlir::MLIRContext *context) -> mlir::Type {
141 return mlir::IntegerType::get(context, 8 * sizeof(int));
142 };
143}
144template <>
145constexpr TypeBuilderFunc getModel<int &>() {
146 return [](mlir::MLIRContext *context) -> mlir::Type {
147 TypeBuilderFunc f{getModel<int>()};
148 return fir::ReferenceType::get(f(context));
149 };
150}
151template <>
152constexpr TypeBuilderFunc getModel<int *>() {
153 return getModel<int &>();
154}
155template <>
156constexpr TypeBuilderFunc getModel<const int *>() {
157 return [](mlir::MLIRContext *context) -> mlir::Type {
158 TypeBuilderFunc f{getModel<int>()};
159 return fir::ReferenceType::get(f(context));
160 };
161}
162template <>
163constexpr TypeBuilderFunc getModel<char *>() {
164 return [](mlir::MLIRContext *context) -> mlir::Type {
165 return fir::ReferenceType::get(mlir::IntegerType::get(context, 8));
166 };
167}
168template <>
169constexpr TypeBuilderFunc getModel<const char *>() {
170 return getModel<char *>();
171}
172template <>
173constexpr TypeBuilderFunc getModel<const char16_t *>() {
174 return [](mlir::MLIRContext *context) -> mlir::Type {
175 return fir::ReferenceType::get(mlir::IntegerType::get(context, 16));
176 };
177}
178template <>
179constexpr TypeBuilderFunc getModel<const char32_t *>() {
180 return [](mlir::MLIRContext *context) -> mlir::Type {
181 return fir::ReferenceType::get(mlir::IntegerType::get(context, 32));
182 };
183}
184template <>
185constexpr TypeBuilderFunc getModel<char>() {
186 return [](mlir::MLIRContext *context) -> mlir::Type {
187 return mlir::IntegerType::get(context, 8 * sizeof(char));
188 };
189}
190template <>
191constexpr TypeBuilderFunc getModel<signed char>() {
192 return [](mlir::MLIRContext *context) -> mlir::Type {
193 return mlir::IntegerType::get(context, 8 * sizeof(signed char));
194 };
195}
196template <>
197constexpr TypeBuilderFunc getModel<signed char *>() {
198 return [](mlir::MLIRContext *context) -> mlir::Type {
199 TypeBuilderFunc f{getModel<signed char>()};
200 return fir::ReferenceType::get(f(context));
201 };
202}
203template <>
204constexpr TypeBuilderFunc getModel<const signed char *>() {
205 return getModel<signed char *>();
206}
207template <>
208constexpr TypeBuilderFunc getModel<char16_t>() {
209 return [](mlir::MLIRContext *context) -> mlir::Type {
210 return mlir::IntegerType::get(context, 8 * sizeof(char16_t));
211 };
212}
213template <>
214constexpr TypeBuilderFunc getModel<char16_t *>() {
215 return [](mlir::MLIRContext *context) -> mlir::Type {
216 TypeBuilderFunc f{getModel<char16_t>()};
217 return fir::ReferenceType::get(f(context));
218 };
219}
220template <>
221constexpr TypeBuilderFunc getModel<char32_t>() {
222 return [](mlir::MLIRContext *context) -> mlir::Type {
223 return mlir::IntegerType::get(context, 8 * sizeof(char32_t));
224 };
225}
226template <>
227constexpr TypeBuilderFunc getModel<char32_t *>() {
228 return [](mlir::MLIRContext *context) -> mlir::Type {
229 TypeBuilderFunc f{getModel<char32_t>()};
230 return fir::ReferenceType::get(f(context));
231 };
232}
233template <>
234constexpr TypeBuilderFunc getModel<unsigned char>() {
235 return [](mlir::MLIRContext *context) -> mlir::Type {
236 return mlir::IntegerType::get(context, 8 * sizeof(unsigned char));
237 };
238}
239template <>
240constexpr TypeBuilderFunc getModel<void *>() {
241 return [](mlir::MLIRContext *context) -> mlir::Type {
242 return fir::LLVMPointerType::get(context,
243 mlir::IntegerType::get(context, 8));
244 };
245}
246template <>
247constexpr TypeBuilderFunc getModel<void (*)(int)>() {
248 return [](mlir::MLIRContext *context) -> mlir::Type {
249 return fir::LLVMPointerType::get(
250 context,
251 mlir::FunctionType::get(context, /*inputs=*/{}, /*results*/ {}));
252 };
253}
254template <>
255constexpr TypeBuilderFunc
256getModel<void *(*)(void *, const void *, unsigned long)>() {
257 return [](mlir::MLIRContext *context) -> mlir::Type {
258 auto voidPtrTy =
259 fir::LLVMPointerType::get(context, mlir::IntegerType::get(context, 8));
260 auto unsignedLongTy =
261 mlir::IntegerType::get(context, 8 * sizeof(unsigned long));
262 auto funcTy = mlir::FunctionType::get(
263 context, {voidPtrTy, voidPtrTy, unsignedLongTy}, {voidPtrTy});
264 return fir::LLVMPointerType::get(context, funcTy);
265 };
266}
267#ifdef _MSC_VER
268template <>
269constexpr TypeBuilderFunc
270getModel<void *(*)(void *, const void *, unsigned __int64)>() {
271 return [](mlir::MLIRContext *context) -> mlir::Type {
272 auto voidPtrTy =
273 fir::LLVMPointerType::get(context, mlir::IntegerType::get(context, 8));
274 auto uint64Ty = mlir::IntegerType::get(context, 64);
275 auto funcTy = mlir::FunctionType::get(
276 context, {voidPtrTy, voidPtrTy, uint64Ty}, {voidPtrTy});
277 return fir::LLVMPointerType::get(context, funcTy);
278 };
279}
280#endif
281template <>
282constexpr TypeBuilderFunc getModel<void (*)(void)>() {
283 return [](mlir::MLIRContext *context) -> mlir::Type {
284 return fir::LLVMPointerType::get(
285 context,
286 mlir::FunctionType::get(context, /*inputs=*/{}, /*results*/ {}));
287 };
288}
289template <>
290constexpr TypeBuilderFunc getModel<void **>() {
291 return [](mlir::MLIRContext *context) -> mlir::Type {
292 return fir::ReferenceType::get(
293 fir::LLVMPointerType::get(context, mlir::IntegerType::get(context, 8)));
294 };
295}
296template <>
297constexpr TypeBuilderFunc getModel<long>() {
298 return [](mlir::MLIRContext *context) -> mlir::Type {
299 return mlir::IntegerType::get(context, 8 * sizeof(long));
300 };
301}
302template <>
303constexpr TypeBuilderFunc getModel<long &>() {
304 return [](mlir::MLIRContext *context) -> mlir::Type {
305 TypeBuilderFunc f{getModel<long>()};
306 return fir::ReferenceType::get(f(context));
307 };
308}
309template <>
310constexpr TypeBuilderFunc getModel<long *>() {
311 return getModel<long &>();
312}
313template <>
314constexpr TypeBuilderFunc getModel<const long *>() {
315 return getModel<long *>();
316}
317template <>
318constexpr TypeBuilderFunc getModel<long long>() {
319 return [](mlir::MLIRContext *context) -> mlir::Type {
320 return mlir::IntegerType::get(context, 8 * sizeof(long long));
321 };
322}
323template <>
324constexpr TypeBuilderFunc getModel<Fortran::common::int128_t>() {
325 return [](mlir::MLIRContext *context) -> mlir::Type {
326 return mlir::IntegerType::get(context,
327 8 * sizeof(Fortran::common::int128_t));
328 };
329}
330template <>
331constexpr TypeBuilderFunc getModel<long long &>() {
332 return [](mlir::MLIRContext *context) -> mlir::Type {
333 TypeBuilderFunc f{getModel<long long>()};
334 return fir::ReferenceType::get(f(context));
335 };
336}
337template <>
338constexpr TypeBuilderFunc getModel<long long *>() {
339 return getModel<long long &>();
340}
341template <>
342constexpr TypeBuilderFunc getModel<const long long *>() {
343 return getModel<long long *>();
344}
345template <>
346constexpr TypeBuilderFunc getModel<unsigned long>() {
347 return [](mlir::MLIRContext *context) -> mlir::Type {
348 return mlir::IntegerType::get(context, 8 * sizeof(unsigned long));
349 };
350}
351template <>
352constexpr TypeBuilderFunc getModel<unsigned long long>() {
353 return [](mlir::MLIRContext *context) -> mlir::Type {
354 return mlir::IntegerType::get(context, 8 * sizeof(unsigned long long));
355 };
356}
357template <>
358constexpr TypeBuilderFunc getModel<double>() {
359 return [](mlir::MLIRContext *context) -> mlir::Type {
360 return mlir::Float64Type::get(context);
361 };
362}
363template <>
364constexpr TypeBuilderFunc getModel<double &>() {
365 return [](mlir::MLIRContext *context) -> mlir::Type {
366 TypeBuilderFunc f{getModel<double>()};
367 return fir::ReferenceType::get(f(context));
368 };
369}
370template <>
371constexpr TypeBuilderFunc getModel<double *>() {
372 return getModel<double &>();
373}
374template <>
375constexpr TypeBuilderFunc getModel<const double *>() {
376 return getModel<double *>();
377}
378template <>
379constexpr TypeBuilderFunc getModel<long double>() {
380 return [](mlir::MLIRContext *context) -> mlir::Type {
381 // See TODO at the top of the file. This is configuring for the host system
382 // - it might be incorrect when cross-compiling!
383 constexpr size_t size = sizeof(long double);
384 static_assert(size == 16 || size == 10 || size == 8,
385 "unsupported long double size");
386 if constexpr (size == 16)
387 return mlir::Float128Type::get(context);
388 if constexpr (size == 10)
389 return mlir::Float80Type::get(context);
390 if constexpr (size == 8)
391 return mlir::Float64Type::get(context);
392 llvm_unreachable("failed static assert");
393 };
394}
395template <>
396constexpr TypeBuilderFunc getModel<long double *>() {
397 return [](mlir::MLIRContext *context) -> mlir::Type {
398 TypeBuilderFunc f{getModel<long double>()};
399 return fir::ReferenceType::get(f(context));
400 };
401}
402template <>
403constexpr TypeBuilderFunc getModel<const long double *>() {
404 return getModel<long double *>();
405}
406template <>
407constexpr TypeBuilderFunc getModel<float>() {
408 return [](mlir::MLIRContext *context) -> mlir::Type {
409 return mlir::Float32Type::get(context);
410 };
411}
412template <>
413constexpr TypeBuilderFunc getModel<float &>() {
414 return [](mlir::MLIRContext *context) -> mlir::Type {
415 TypeBuilderFunc f{getModel<float>()};
416 return fir::ReferenceType::get(f(context));
417 };
418}
419template <>
420constexpr TypeBuilderFunc getModel<float *>() {
421 return getModel<float &>();
422}
423template <>
424constexpr TypeBuilderFunc getModel<const float *>() {
425 return getModel<float *>();
426}
427template <>
428constexpr TypeBuilderFunc getModel<bool>() {
429 return [](mlir::MLIRContext *context) -> mlir::Type {
430 return mlir::IntegerType::get(context, 1);
431 };
432}
433template <>
434constexpr TypeBuilderFunc getModel<bool &>() {
435 return [](mlir::MLIRContext *context) -> mlir::Type {
436 TypeBuilderFunc f{getModel<bool>()};
437 return fir::ReferenceType::get(f(context));
438 };
439}
440template <>
441constexpr TypeBuilderFunc getModel<bool *>() {
442 return [](mlir::MLIRContext *context) -> mlir::Type {
443 TypeBuilderFunc f{getModel<bool>()};
444 return fir::ReferenceType::get(f(context));
445 };
446}
447template <>
448constexpr TypeBuilderFunc getModel<unsigned short>() {
449 return [](mlir::MLIRContext *context) -> mlir::Type {
450 return mlir::IntegerType::get(
451 context, 8 * sizeof(unsigned short),
452 mlir::IntegerType::SignednessSemantics::Unsigned);
453 };
454}
455template <>
456constexpr TypeBuilderFunc getModel<unsigned char *>() {
457 return [](mlir::MLIRContext *context) -> mlir::Type {
458 return fir::ReferenceType::get(mlir::IntegerType::get(context, 8));
459 };
460}
461template <>
462constexpr TypeBuilderFunc getModel<const unsigned char *>() {
463 return getModel<unsigned char *>();
464}
465template <>
466constexpr TypeBuilderFunc getModel<unsigned short *>() {
467 return [](mlir::MLIRContext *context) -> mlir::Type {
468 return fir::ReferenceType::get(
469 mlir::IntegerType::get(context, 8 * sizeof(unsigned short)));
470 };
471}
472template <>
473constexpr TypeBuilderFunc getModel<const unsigned short *>() {
474 return getModel<unsigned short *>();
475}
476template <>
477constexpr TypeBuilderFunc getModel<unsigned *>() {
478 return getModel<int *>();
479}
480template <>
481constexpr TypeBuilderFunc getModel<const unsigned *>() {
482 return getModel<unsigned *>();
483}
484template <>
485constexpr TypeBuilderFunc getModel<unsigned long *>() {
486 return [](mlir::MLIRContext *context) -> mlir::Type {
487 return fir::ReferenceType::get(
488 mlir::IntegerType::get(context, 8 * sizeof(unsigned long)));
489 };
490}
491template <>
492constexpr TypeBuilderFunc getModel<const unsigned long *>() {
493 return getModel<unsigned long *>();
494}
495template <>
496constexpr TypeBuilderFunc getModel<unsigned long long *>() {
497 return [](mlir::MLIRContext *context) -> mlir::Type {
498 return fir::ReferenceType::get(
499 mlir::IntegerType::get(context, 8 * sizeof(unsigned long long)));
500 };
501}
502template <>
503constexpr TypeBuilderFunc getModel<const unsigned long long *>() {
504 return getModel<unsigned long long *>();
505}
506template <>
507constexpr TypeBuilderFunc getModel<Fortran::common::uint128_t>() {
508 return getModel<Fortran::common::int128_t>();
509}
510template <>
511constexpr TypeBuilderFunc getModel<Fortran::common::int128_t *>() {
512 return [](mlir::MLIRContext *context) -> mlir::Type {
513 TypeBuilderFunc f{getModel<Fortran::common::int128_t>()};
514 return fir::ReferenceType::get(f(context));
515 };
516}
517template <>
518constexpr TypeBuilderFunc getModel<Fortran::common::uint128_t *>() {
519 return getModel<Fortran::common::int128_t *>();
520}
521template <>
522constexpr TypeBuilderFunc getModel<const Fortran::common::uint128_t *>() {
523 return getModel<Fortran::common::uint128_t *>();
524}
525
526// getModel<std::complex<T>> are not implemented on purpose.
527// Prefer passing/returning the complex by reference in the runtime to
528// avoid ABI issues.
529// C++ std::complex is not an intrinsic type, and while it is storage
530// compatible with C/Fortran complex type, it follows the struct value passing
531// ABI rule, which may differ from how C complex are passed on some platforms.
532
533template <>
534constexpr TypeBuilderFunc getModel<std::complex<float> &>() {
535 return [](mlir::MLIRContext *context) -> mlir::Type {
536 mlir::Type floatTy = getModel<float>()(context);
537 return fir::ReferenceType::get(mlir::ComplexType::get(floatTy));
538 };
539}
540template <>
541constexpr TypeBuilderFunc getModel<std::complex<float> *>() {
542 return getModel<std::complex<float> &>();
543}
544template <>
545constexpr TypeBuilderFunc getModel<const std::complex<float> *>() {
546 return getModel<std::complex<float> *>();
547}
548template <>
549constexpr TypeBuilderFunc getModel<std::complex<double> &>() {
550 return [](mlir::MLIRContext *context) -> mlir::Type {
551 mlir::Type floatTy = getModel<double>()(context);
552 return fir::ReferenceType::get(mlir::ComplexType::get(floatTy));
553 };
554}
555template <>
556constexpr TypeBuilderFunc getModel<std::complex<double> *>() {
557 return getModel<std::complex<double> &>();
558}
559template <>
560constexpr TypeBuilderFunc getModel<const std::complex<double> *>() {
561 return getModel<std::complex<double> *>();
562}
563template <>
564constexpr TypeBuilderFunc getModel<c_float_complex_t>() {
565 return [](mlir::MLIRContext *context) -> mlir::Type {
566 mlir::Type floatTy = getModel<float>()(context);
567 return mlir::ComplexType::get(floatTy);
568 };
569}
570template <>
571constexpr TypeBuilderFunc getModel<c_double_complex_t>() {
572 return [](mlir::MLIRContext *context) -> mlir::Type {
573 mlir::Type floatTy = getModel<double>()(context);
574 return mlir::ComplexType::get(floatTy);
575 };
576}
577template <>
578constexpr TypeBuilderFunc getModel<const Fortran::runtime::Descriptor &>() {
579 return [](mlir::MLIRContext *context) -> mlir::Type {
580 return fir::BoxType::get(mlir::NoneType::get(context));
581 };
582}
583template <>
584constexpr TypeBuilderFunc getModel<Fortran::runtime::Descriptor &>() {
585 return [](mlir::MLIRContext *context) -> mlir::Type {
586 return fir::ReferenceType::get(
587 fir::BoxType::get(mlir::NoneType::get(context)));
588 };
589}
590template <>
591constexpr TypeBuilderFunc getModel<const Fortran::runtime::Descriptor *>() {
592 return getModel<const Fortran::runtime::Descriptor &>();
593}
594template <>
595constexpr TypeBuilderFunc getModel<Fortran::runtime::Descriptor *>() {
596 return getModel<Fortran::runtime::Descriptor &>();
597}
598template <>
599constexpr TypeBuilderFunc getModel<Fortran::common::TypeCategory>() {
600 return [](mlir::MLIRContext *context) -> mlir::Type {
601 return mlir::IntegerType::get(context,
602 sizeof(Fortran::common::TypeCategory) * 8);
603 };
604}
605template <>
606constexpr TypeBuilderFunc
607getModel<const Fortran::runtime::typeInfo::DerivedType &>() {
608 return [](mlir::MLIRContext *context) -> mlir::Type {
609 return fir::ReferenceType::get(mlir::NoneType::get(context));
610 };
611}
612template <>
613constexpr TypeBuilderFunc
614getModel<const Fortran::runtime::typeInfo::DerivedType *>() {
615 return [](mlir::MLIRContext *context) -> mlir::Type {
616 return fir::ReferenceType::get(mlir::NoneType::get(context));
617 };
618}
619template <>
620constexpr TypeBuilderFunc getModel<void>() {
621 return [](mlir::MLIRContext *context) -> mlir::Type {
622 return mlir::NoneType::get(context);
623 };
624}
625
626// Define additional runtime type models specific to IO.
627template <>
628constexpr TypeBuilderFunc getModel<Fortran::runtime::io::IoStatementState *>() {
629 return getModel<char *>();
630}
631template <>
632constexpr TypeBuilderFunc getModel<Fortran::runtime::io::Iostat>() {
633 return [](mlir::MLIRContext *context) -> mlir::Type {
634 return mlir::IntegerType::get(context,
635 8 * sizeof(Fortran::runtime::io::Iostat));
636 };
637}
638template <>
639constexpr TypeBuilderFunc
640getModel<const Fortran::runtime::io::NamelistGroup &>() {
641 return [](mlir::MLIRContext *context) -> mlir::Type {
642 return fir::ReferenceType::get(mlir::TupleType::get(context));
643 };
644}
645template <>
646constexpr TypeBuilderFunc
647getModel<const Fortran::runtime::io::NonTbpDefinedIoTable *>() {
648 return [](mlir::MLIRContext *context) -> mlir::Type {
649 return fir::ReferenceType::get(mlir::TupleType::get(context));
650 };
651}
652
653REDUCTION_REF_OPERATION_MODEL(std::int8_t)
654REDUCTION_VALUE_OPERATION_MODEL(std::int8_t)
655REDUCTION_REF_OPERATION_MODEL(std::int16_t)
656REDUCTION_VALUE_OPERATION_MODEL(std::int16_t)
657REDUCTION_REF_OPERATION_MODEL(std::int32_t)
658REDUCTION_VALUE_OPERATION_MODEL(std::int32_t)
659REDUCTION_REF_OPERATION_MODEL(std::int64_t)
660REDUCTION_VALUE_OPERATION_MODEL(std::int64_t)
661REDUCTION_REF_OPERATION_MODEL(Fortran::common::int128_t)
662REDUCTION_VALUE_OPERATION_MODEL(Fortran::common::int128_t)
663
664REDUCTION_REF_OPERATION_MODEL(std::uint8_t)
665REDUCTION_VALUE_OPERATION_MODEL(std::uint8_t)
666REDUCTION_REF_OPERATION_MODEL(std::uint16_t)
667REDUCTION_VALUE_OPERATION_MODEL(std::uint16_t)
668REDUCTION_REF_OPERATION_MODEL(std::uint32_t)
669REDUCTION_VALUE_OPERATION_MODEL(std::uint32_t)
670REDUCTION_REF_OPERATION_MODEL(std::uint64_t)
671REDUCTION_VALUE_OPERATION_MODEL(std::uint64_t)
672REDUCTION_REF_OPERATION_MODEL(Fortran::common::uint128_t)
673REDUCTION_VALUE_OPERATION_MODEL(Fortran::common::uint128_t)
674
675REDUCTION_REF_OPERATION_MODEL(float)
676REDUCTION_VALUE_OPERATION_MODEL(float)
677REDUCTION_REF_OPERATION_MODEL(double)
678REDUCTION_VALUE_OPERATION_MODEL(double)
679REDUCTION_REF_OPERATION_MODEL(long double)
680REDUCTION_VALUE_OPERATION_MODEL(long double)
681
682// FIXME: the runtime is not using the correct ABIs when calling complex
683// callbacks. lowering either need to create wrappers or just have an inline
684// implementation for it. https://github.com/llvm/llvm-project/issues/110674
685template <>
686constexpr TypeBuilderFunc
687getModel<Fortran::runtime::ValueReductionOperation<std::complex<float>>>() {
688 return [](mlir::MLIRContext *context) -> mlir::Type {
689 mlir::Type cplx = mlir::ComplexType::get(getModel<float>()(context));
690 auto refTy = fir::ReferenceType::get(cplx);
691 return mlir::FunctionType::get(context, {cplx, cplx}, refTy);
692 };
693}
694template <>
695constexpr TypeBuilderFunc
696getModel<Fortran::runtime::ValueReductionOperation<std::complex<double>>>() {
697 return [](mlir::MLIRContext *context) -> mlir::Type {
698 mlir::Type cplx = mlir::ComplexType::get(getModel<double>()(context));
699 auto refTy = fir::ReferenceType::get(cplx);
700 return mlir::FunctionType::get(context, {cplx, cplx}, refTy);
701 };
702}
703template <>
704constexpr TypeBuilderFunc
705getModel<Fortran::runtime::ReferenceReductionOperation<std::complex<float>>>() {
706 return [](mlir::MLIRContext *context) -> mlir::Type {
707 mlir::Type cplx = mlir::ComplexType::get(getModel<float>()(context));
708 auto refTy = fir::ReferenceType::get(cplx);
709 return mlir::FunctionType::get(context, {refTy, refTy}, refTy);
710 };
711}
712template <>
713constexpr TypeBuilderFunc getModel<
714 Fortran::runtime::ReferenceReductionOperation<std::complex<double>>>() {
715 return [](mlir::MLIRContext *context) -> mlir::Type {
716 mlir::Type cplx = mlir::ComplexType::get(getModel<double>()(context));
717 auto refTy = fir::ReferenceType::get(cplx);
718 return mlir::FunctionType::get(context, {refTy, refTy}, refTy);
719 };
720}
721
722REDUCTION_CHAR_OPERATION_MODEL(char)
723REDUCTION_CHAR_OPERATION_MODEL(char16_t)
724REDUCTION_CHAR_OPERATION_MODEL(char32_t)
725
726template <>
727constexpr TypeBuilderFunc
728getModel<Fortran::runtime::ReductionDerivedTypeOperation>() {
729 return [](mlir::MLIRContext *context) -> mlir::Type {
730 auto voidTy =
731 fir::LLVMPointerType::get(context, mlir::IntegerType::get(context, 8));
732 return mlir::FunctionType::get(context, {voidTy, voidTy, voidTy}, voidTy);
733 };
734}
735
736template <typename...>
738template <typename RT, typename... ATs>
739struct RuntimeTableKey<RT(ATs...)> {
740 static constexpr FuncTypeBuilderFunc getTypeModel() {
741 return [](mlir::MLIRContext *ctxt) {
742 TypeBuilderFunc ret = getModel<RT>();
743 std::array<TypeBuilderFunc, sizeof...(ATs)> args = {getModel<ATs>()...};
744 mlir::Type retTy = ret(ctxt);
745 llvm::SmallVector<mlir::Type, sizeof...(ATs)> argTys;
746 for (auto f : args)
747 argTys.push_back(f(ctxt));
748 if (mlir::isa<mlir::NoneType>(retTy))
749 return mlir::FunctionType::get(ctxt, argTys, {});
750 return mlir::FunctionType::get(ctxt, argTys, {retTy});
751 };
752 }
753};
754
755//===----------------------------------------------------------------------===//
756// Runtime table building (constexpr folded)
757//===----------------------------------------------------------------------===//
758
759template <char... Cs>
760using RuntimeIdentifier = std::integer_sequence<char, Cs...>;
761
762namespace details {
763template <typename T, T... As, T... Bs>
764static constexpr std::integer_sequence<T, As..., Bs...>
765concat(std::integer_sequence<T, As...>, std::integer_sequence<T, Bs...>) {
766 return {};
767}
768template <typename T, T... As, T... Bs, typename... Cs>
769static constexpr auto concat(std::integer_sequence<T, As...>,
770 std::integer_sequence<T, Bs...>, Cs...) {
771 return concat(std::integer_sequence<T, As..., Bs...>{}, Cs{}...);
772}
773template <typename T>
774static constexpr std::integer_sequence<T> concat(std::integer_sequence<T>) {
775 return {};
776}
777template <typename T, T a>
778static constexpr auto filterZero(std::integer_sequence<T, a>) {
779 if constexpr (a != 0) {
780 return std::integer_sequence<T, a>{};
781 } else {
782 return std::integer_sequence<T>{};
783 }
784}
785template <typename T, T... b>
786static constexpr auto filter(std::integer_sequence<T, b...>) {
787 if constexpr (sizeof...(b) > 0) {
788 return details::concat(filterZero(std::integer_sequence<T, b>{})...);
789 } else {
790 return std::integer_sequence<T>{};
791 }
792}
793} // namespace details
794
795template <typename...>
797template <typename KT, char... Cs>
798struct RuntimeTableEntry<RuntimeTableKey<KT>, RuntimeIdentifier<Cs...>> {
799 static constexpr FuncTypeBuilderFunc getTypeModel() {
801 }
802 static constexpr const char name[sizeof...(Cs) + 1] = {Cs..., '\0'};
803};
804
816#undef FirE
817#define FirE(L, I) (I < sizeof(L) / sizeof(*L) ? L[I] : 0)
818#define FirQuoteKey(X) #X
819#define ExpandAndQuoteKey(X) FirQuoteKey(X)
820#define FirMacroExpandKey(X) \
821 FirE(X, 0), FirE(X, 1), FirE(X, 2), FirE(X, 3), FirE(X, 4), FirE(X, 5), \
822 FirE(X, 6), FirE(X, 7), FirE(X, 8), FirE(X, 9), FirE(X, 10), \
823 FirE(X, 11), FirE(X, 12), FirE(X, 13), FirE(X, 14), FirE(X, 15), \
824 FirE(X, 16), FirE(X, 17), FirE(X, 18), FirE(X, 19), FirE(X, 20), \
825 FirE(X, 21), FirE(X, 22), FirE(X, 23), FirE(X, 24), FirE(X, 25), \
826 FirE(X, 26), FirE(X, 27), FirE(X, 28), FirE(X, 29), FirE(X, 30), \
827 FirE(X, 31), FirE(X, 32), FirE(X, 33), FirE(X, 34), FirE(X, 35), \
828 FirE(X, 36), FirE(X, 37), FirE(X, 38), FirE(X, 39), FirE(X, 40), \
829 FirE(X, 41), FirE(X, 42), FirE(X, 43), FirE(X, 44), FirE(X, 45), \
830 FirE(X, 46), FirE(X, 47), FirE(X, 48), FirE(X, 49)
831#define FirExpandKey(X) FirMacroExpandKey(FirQuoteKey(X))
832#define FirFullSeq(X) std::integer_sequence<char, FirExpandKey(X)>
833#define FirAsSequence(X) \
834 decltype(fir::runtime::details::filter(FirFullSeq(X){}))
835#define FirmkKey(X) \
836 fir::runtime::RuntimeTableEntry<fir::runtime::RuntimeTableKey<decltype(X)>, \
837 FirAsSequence(X)>
838#define mkRTKey(X) FirmkKey(RTNAME(X))
839#define EXPAND_AND_QUOTE_KEY(S) ExpandAndQuoteKey(RTNAME(S))
840
843template <typename RuntimeEntry>
844static mlir::func::FuncOp getRuntimeFunc(mlir::Location loc,
845 fir::FirOpBuilder &builder,
846 bool isIO = false) {
847 using namespace Fortran::runtime;
848 auto name = RuntimeEntry::name;
849 auto func = builder.getNamedFunction(name);
850 if (func)
851 return func;
852 auto funTy = RuntimeEntry::getTypeModel()(builder.getContext());
853 return builder.createRuntimeFunction(loc, name, funTy, isIO);
854}
855
857template <typename E>
858static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
859 fir::FirOpBuilder &builder) {
860 return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
861}
862
863inline llvm::SmallVector<mlir::Value>
864createArguments(fir::FirOpBuilder &builder, mlir::Location loc,
865 mlir::FunctionType fTy, llvm::ArrayRef<mlir::Value> args) {
866 return llvm::map_to_vector(llvm::zip_equal(fTy.getInputs(), args),
867 [&](const auto &pair) -> mlir::Value {
868 auto [type, argument] = pair;
869 return builder.createConvertWithVolatileCast(
870 loc, type, argument);
871 });
872}
873
875template <typename... As>
876llvm::SmallVector<mlir::Value>
877createArguments(fir::FirOpBuilder &builder, mlir::Location loc,
878 mlir::FunctionType fTy, As... args) {
879 return createArguments(builder, loc, fTy, {args...});
880}
881
882} // namespace fir::runtime
883
884#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_RTBUILDER_H
Definition FIRBuilder.h:55
mlir::func::FuncOp createRuntimeFunction(mlir::Location loc, llvm::StringRef name, mlir::FunctionType ty, bool isIO=false)
Definition FIRBuilder.cpp:52
mlir::func::FuncOp getNamedFunction(llvm::StringRef name)
Definition FIRBuilder.h:394
Definition OpenACC.h:20
Definition RTBuilder.h:796
Definition RTBuilder.h:737