FLANG
IntrinsicCall.h
1//===-- Builder/IntrinsicCall.h -- lowering of intrinsics -------*- 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#ifndef FORTRAN_LOWER_INTRINSICCALL_H
10#define FORTRAN_LOWER_INTRINSICCALL_H
11
12#include "flang/Optimizer/Builder/BoxValue.h"
13#include "flang/Optimizer/Builder/FIRBuilder.h"
14#include "flang/Optimizer/Builder/Runtime/Character.h"
15#include "flang/Optimizer/Builder/Runtime/Numeric.h"
17#include "flang/Runtime/entry-names.h"
18#include "flang/Runtime/iostat-consts.h"
19#include "mlir/Dialect/Complex/IR/Complex.h"
20#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
21#include "mlir/Dialect/Math/IR/Math.h"
22#include <optional>
23
24namespace Fortran {
25namespace lower {
26// TODO: remove the usage of AbstractConverter to avoid making IntrinsicCall.cpp
27// depend upon Lower/Evaluate and use a data structure to pass options to
28// IntrinsicLibrary.
30} // namespace lower
31} // namespace Fortran
32
33namespace fir {
34
35class StatementContext;
37
43std::pair<fir::ExtendedValue, bool>
44genIntrinsicCall(fir::FirOpBuilder &, mlir::Location, llvm::StringRef name,
45 std::optional<mlir::Type> resultType,
46 llvm::ArrayRef<fir::ExtendedValue> args,
47 Fortran::lower::AbstractConverter *converter = nullptr);
48
52std::pair<fir::ExtendedValue, bool>
53genIntrinsicCall(fir::FirOpBuilder &, mlir::Location,
55 std::optional<mlir::Type> resultType,
56 llvm::ArrayRef<fir::ExtendedValue> args,
57 Fortran::lower::AbstractConverter *converter = nullptr);
58
60enum class Extremum { Min, Max };
61
62// There are different ways to deal with NaNs in MIN and MAX.
63// Known existing behaviors are listed below and can be selected for
64// f18 MIN/MAX implementation.
65enum class ExtremumBehavior {
66 // Note: the Signaling/quiet aspect of NaNs in the behaviors below are
67 // not described because there is no way to control/observe such aspect in
68 // MLIR/LLVM yet. The IEEE behaviors come with requirements regarding this
69 // aspect that are therefore currently not enforced. In the descriptions
70 // below, NaNs can be signaling or quite. Returned NaNs may be signaling
71 // if one of the input NaN was signaling but it cannot be guaranteed either.
72 // Existing compilers using an IEEE behavior (gfortran) also do not fulfill
73 // signaling/quiet requirements.
74 IeeeMinMaximumNumber,
75 // IEEE minimumNumber/maximumNumber behavior (754-2019, section 9.6):
76 // If one of the argument is and number and the other is NaN, return the
77 // number. If both arguements are NaN, return NaN.
78 // Compilers: gfortran.
79 IeeeMinMaximum,
80 // IEEE minimum/maximum behavior (754-2019, section 9.6):
81 // If one of the argument is NaN, return NaN.
82 MinMaxss,
83 // x86 minss/maxss behavior:
84 // If the second argument is a number and the other is NaN, return the number.
85 // In all other cases where at least one operand is NaN, return NaN.
86 // Compilers: xlf (only for MAX), ifort, pgfortran -nollvm, and nagfor.
87 PgfortranLlvm,
88 // "Opposite of" x86 minss/maxss behavior:
89 // If the first argument is a number and the other is NaN, return the
90 // number.
91 // In all other cases where at least one operand is NaN, return NaN.
92 // Compilers: xlf (only for MIN), and pgfortran (with llvm).
93 IeeeMinMaxNum
94 // IEEE minNum/maxNum behavior (754-2008, section 5.3.1):
95 // TODO: Not implemented.
96 // It is the only behavior where the signaling/quiet aspect of a NaN argument
97 // impacts if the result should be NaN or the argument that is a number.
98 // LLVM/MLIR do not provide ways to observe this aspect, so it is not
99 // possible to implement it without some target dependent runtime.
100};
101
117
120 LowerIntrinsicArgAs lowerAs;
122 // - Numerical: 0
123 // - Logical : false
124 // - Derived/character: not possible. Need custom intrinsic lowering.
125 // Addr:
126 // - nullptr
127 // Box:
128 // - absent box
129 // AsInquired:
130 // - no-op
132};
133
134constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
135constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
136constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
137constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired;
138
142
143// TODO error handling -> return a code or directly emit messages ?
144struct IntrinsicLibrary {
145
146 // Constructors.
147 explicit IntrinsicLibrary(
148 fir::FirOpBuilder &builder, mlir::Location loc,
149 Fortran::lower::AbstractConverter *converter = nullptr)
150 : builder{builder}, loc{loc}, converter{converter} {}
151 IntrinsicLibrary() = delete;
152 IntrinsicLibrary(const IntrinsicLibrary &) = delete;
153
157 std::pair<fir::ExtendedValue, bool>
158 genIntrinsicCall(llvm::StringRef name, std::optional<mlir::Type> resultType,
160
168 mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type,
170
171 using RuntimeCallGenerator = std::function<mlir::Value(
173 RuntimeCallGenerator
174 getRuntimeCallGenerator(llvm::StringRef name,
175 mlir::FunctionType soughtFuncType);
176
182 mlir::Value genAbs(mlir::Type, llvm::ArrayRef<mlir::Value>);
183 mlir::Value genAcosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
184 mlir::Value genAcospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
185 template <void (*CallRuntime)(fir::FirOpBuilder &, mlir::Location loc,
186 mlir::Value, mlir::Value)>
187 fir::ExtendedValue genAdjustRtCall(mlir::Type,
189 mlir::Value genAimag(mlir::Type, llvm::ArrayRef<mlir::Value>);
190 mlir::Value genAint(mlir::Type, llvm::ArrayRef<mlir::Value>);
192 fir::ExtendedValue genAllocated(mlir::Type,
194 mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
196 mlir::Value genAtanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
198 genCommandArgumentCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
199 mlir::Value genAsind(mlir::Type, llvm::ArrayRef<mlir::Value>);
200 mlir::Value genAsinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
201 fir::ExtendedValue genAssociated(mlir::Type,
203 mlir::Value genAtand(mlir::Type, llvm::ArrayRef<mlir::Value>);
204 fir::ExtendedValue genBesselJn(mlir::Type,
206 fir::ExtendedValue genBesselYn(mlir::Type,
208 template <mlir::arith::CmpIPredicate pred>
209 mlir::Value genBitwiseCompare(mlir::Type resultType,
211
212 mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
213 mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
215 fir::ExtendedValue genChdir(std::optional<mlir::Type> resultType,
217 template <mlir::arith::CmpIPredicate pred>
218 fir::ExtendedValue genCharacterCompare(mlir::Type,
220 mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
221 mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
223 void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
230 mlir::Value genErfcScaled(mlir::Type resultType,
232 void genCFPointer(llvm::ArrayRef<fir::ExtendedValue>);
233 void genCFProcPointer(llvm::ArrayRef<fir::ExtendedValue>);
234 void genCFStrPointer(llvm::ArrayRef<fir::ExtendedValue>);
237 template <mlir::arith::CmpIPredicate pred>
238 fir::ExtendedValue genCPtrCompare(mlir::Type,
240 void genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue>);
244 mlir::Value genCosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
245 mlir::Value genCospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
246 void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
247 fir::ExtendedValue genDsecnds(mlir::Type resultType,
249 mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
250 fir::ExtendedValue genDotProduct(mlir::Type,
252 mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
253 mlir::Value genDshiftl(mlir::Type, llvm::ArrayRef<mlir::Value>);
254 mlir::Value genDshiftr(mlir::Type, llvm::ArrayRef<mlir::Value>);
257 void genExecuteCommandLine(mlir::ArrayRef<fir::ExtendedValue> args);
258 fir::ExtendedValue genEtime(std::optional<mlir::Type>,
259 mlir::ArrayRef<fir::ExtendedValue> args);
260 mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
261 fir::ExtendedValue genExtendsTypeOf(mlir::Type,
263 template <Extremum, ExtremumBehavior>
264 mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
265 fir::ExtendedValue genFCString(mlir::Type,
267 mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
269 mlir::Value genFraction(mlir::Type resultType,
270 mlir::ArrayRef<mlir::Value> args);
271 void genFree(mlir::ArrayRef<fir::ExtendedValue> args);
272 fir::ExtendedValue genFseek(std::optional<mlir::Type>,
273 mlir::ArrayRef<fir::ExtendedValue> args);
274 fir::ExtendedValue genFtell(std::optional<mlir::Type>,
275 mlir::ArrayRef<fir::ExtendedValue> args);
276 fir::ExtendedValue genGetCwd(std::optional<mlir::Type> resultType,
278 void genGetCommand(mlir::ArrayRef<fir::ExtendedValue> args);
279 mlir::Value genGetPID(mlir::Type resultType,
281 void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
282 void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
283 mlir::Value genGetGID(mlir::Type resultType,
285 mlir::Value genGetTeam(mlir::Type, llvm::ArrayRef<mlir::Value>);
286 mlir::Value genGetUID(mlir::Type resultType,
288 fir::ExtendedValue genHostnm(std::optional<mlir::Type> resultType,
291 mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
293 mlir::Value genIbclr(mlir::Type, llvm::ArrayRef<mlir::Value>);
294 mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
295 mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
298 mlir::Value genIeeeClass(mlir::Type, llvm::ArrayRef<mlir::Value>);
299 mlir::Value genIeeeCopySign(mlir::Type, llvm::ArrayRef<mlir::Value>);
300 void genIeeeGetFlag(llvm::ArrayRef<fir::ExtendedValue>);
301 void genIeeeGetHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
302 template <bool isGet, bool isModes>
303 void genIeeeGetOrSetModesOrStatus(llvm::ArrayRef<fir::ExtendedValue>);
304 void genIeeeGetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
305 void genIeeeGetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
306 mlir::Value genIeeeInt(mlir::Type, llvm::ArrayRef<mlir::Value>);
307 mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
308 mlir::Value genIeeeIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
309 mlir::Value genIeeeIsNegative(mlir::Type, llvm::ArrayRef<mlir::Value>);
310 mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef<mlir::Value>);
311 mlir::Value genIeeeLogb(mlir::Type, mlir::ArrayRef<mlir::Value>);
312 template <bool isMax, bool isNum, bool isMag>
313 mlir::Value genIeeeMaxMin(mlir::Type, llvm::ArrayRef<mlir::Value>);
314 template <mlir::arith::CmpFPredicate pred>
315 mlir::Value genIeeeQuietCompare(mlir::Type resultType,
317 mlir::Value genIeeeReal(mlir::Type, llvm::ArrayRef<mlir::Value>);
318 mlir::Value genIeeeRem(mlir::Type, llvm::ArrayRef<mlir::Value>);
319 mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
320 template <bool isFlag>
321 void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
322 void genIeeeSetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
323 void genIeeeSetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
324 template <mlir::arith::CmpFPredicate pred>
325 mlir::Value genIeeeSignalingCompare(mlir::Type resultType,
327 mlir::Value genIeeeSignbit(mlir::Type, llvm::ArrayRef<mlir::Value>);
328 fir::ExtendedValue genIeeeSupportFlag(mlir::Type,
330 fir::ExtendedValue genIeeeSupportHalting(mlir::Type,
332 fir::ExtendedValue genIeeeSupportRounding(mlir::Type,
334 fir::ExtendedValue genIeeeSupportStandard(mlir::Type,
336 template <mlir::arith::CmpIPredicate pred>
337 mlir::Value genIeeeTypeCompare(mlir::Type, llvm::ArrayRef<mlir::Value>);
338 mlir::Value genIeeeUnordered(mlir::Type, llvm::ArrayRef<mlir::Value>);
339 mlir::Value genIeeeValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
340 mlir::Value genIeor(mlir::Type, llvm::ArrayRef<mlir::Value>);
342 mlir::Value genIor(mlir::Type, llvm::ArrayRef<mlir::Value>);
344 fir::ExtendedValue genIrand(mlir::Type resultType,
346 fir::ExtendedValue genIsContiguous(mlir::Type,
348 template <Fortran::runtime::io::Iostat value>
349 mlir::Value genIsIostatValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
350 mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef<mlir::Value>,
351 int fpclass);
352 mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
353 mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
355 mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
359 mlir::Value genMalloc(mlir::Type, llvm::ArrayRef<mlir::Value>);
360 template <typename Shift>
361 mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
363 fir::ExtendedValue genMatmulTranspose(mlir::Type,
368 mlir::Value genMergeBits(mlir::Type, llvm::ArrayRef<mlir::Value>);
371 mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
372 mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
373 void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
375 enum class NearestProc { Nearest, NextAfter, NextDown, NextUp };
376 template <NearestProc>
377 mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
378 mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
380 mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
382 fir::ExtendedValue genNumImages(mlir::Type,
387 mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
388 mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
391 fir::ExtendedValue genPutenv(std::optional<mlir::Type>,
393 fir::ExtendedValue genRand(mlir::Type resultType,
395 void genRandomInit(llvm::ArrayRef<fir::ExtendedValue>);
396 void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
397 void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
399 fir::ExtendedValue genReduceDim(mlir::Type,
401 fir::ExtendedValue genRename(std::optional<mlir::Type>,
402 mlir::ArrayRef<fir::ExtendedValue>);
405 mlir::Value genRRSpacing(mlir::Type resultType,
407 mlir::Value genRtc(mlir::Type resultType, llvm::ArrayRef<mlir::Value> args);
408 fir::ExtendedValue genSameTypeAs(mlir::Type,
410 mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
412 fir::ExtendedValue genSecnds(mlir::Type resultType,
414 fir::ExtendedValue genSecond(std::optional<mlir::Type>,
415 mlir::ArrayRef<fir::ExtendedValue>);
416 fir::ExtendedValue genSelectedCharKind(mlir::Type,
418 mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
419 mlir::Value genSelectedLogicalKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
420 mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
421 mlir::Value genSetExponent(mlir::Type resultType,
423 fir::ExtendedValue genShape(mlir::Type resultType,
425 template <typename Shift>
426 mlir::Value genShift(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
427 mlir::Value genShiftA(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
428 void genShowDescriptor(llvm::ArrayRef<fir::ExtendedValue>);
429 mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
430 mlir::Value genSind(mlir::Type, llvm::ArrayRef<mlir::Value>);
431 mlir::Value genSinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
434 mlir::Value genSpacing(mlir::Type resultType,
437 fir::ExtendedValue genStorageSize(mlir::Type,
440 void genSignalSubroutine(llvm::ArrayRef<fir::ExtendedValue>);
442 fir::ExtendedValue genSystem(std::optional<mlir::Type>,
443 mlir::ArrayRef<fir::ExtendedValue> args);
444 void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
445 mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
446 mlir::Value genTanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
447 fir::ExtendedValue genTeamNumber(mlir::Type,
449 mlir::Value genTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
450 void genTokenize(llvm::ArrayRef<fir::ExtendedValue>);
451 mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
452 fir::ExtendedValue genTransfer(mlir::Type,
454 fir::ExtendedValue genTranspose(mlir::Type,
456 fir::ExtendedValue genThisImage(mlir::Type,
460 fir::ExtendedValue genUnlink(std::optional<mlir::Type> resultType,
464
468 mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
469
475 template <typename FN, typename FD>
476 fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg,
477 mlir::Type,
479 template <typename FN, typename FD, typename FC>
481 fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar,
482 llvm::StringRef errMsg,
483 mlir::Type resultType,
486 template <typename FN, typename FD>
487 fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg,
488 mlir::Type resultType,
490
493 void genRaiseExcept(int excepts, mlir::Value cond = {});
494
496 mlir::Value genQNan(mlir::Type resultType);
497
501 using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
502 using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
504 using DualGenerator = decltype(&IntrinsicLibrary::genEtime);
505 using Generator = std::variant<ElementalGenerator, ExtendedGenerator,
506 SubroutineGenerator, DualGenerator>;
507
514 template <typename GeneratorType>
515 mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name,
516 mlir::Type resultType,
518 template <typename GeneratorType>
520 outlineInExtendedWrapper(GeneratorType, llvm::StringRef name,
521 std::optional<mlir::Type> resultType,
523
524 template <typename GeneratorType>
525 mlir::func::FuncOp getWrapper(GeneratorType, llvm::StringRef name,
526 mlir::FunctionType,
527 bool loadRefArguments = false);
528
530 template <typename GeneratorType>
532 genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType,
533 llvm::ArrayRef<fir::ExtendedValue> args, bool outline);
534
536 mlir::Value invokeGenerator(ElementalGenerator generator,
537 mlir::Type resultType,
539 mlir::Value invokeGenerator(RuntimeCallGenerator generator,
540 mlir::Type resultType,
542 mlir::Value invokeGenerator(ExtendedGenerator generator,
543 mlir::Type resultType,
545 mlir::Value invokeGenerator(SubroutineGenerator generator,
547 mlir::Value invokeGenerator(DualGenerator generator,
549 mlir::Value invokeGenerator(DualGenerator generator, mlir::Type resultType,
551
554 mlir::SymbolRefAttr
555 getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name,
556 mlir::FunctionType signature);
557
560 mlir::Type resultType,
561 llvm::StringRef errMsg);
562
563 void setResultMustBeFreed() { resultMustBeFreed = true; }
564
565 fir::FirOpBuilder &builder;
566 mlir::Location loc;
567 bool resultMustBeFreed = false;
568 Fortran::lower::AbstractConverter *converter = nullptr;
569};
570
572 const char *name = nullptr;
574 bool handleDynamicOptional = false;
575};
576
581 constexpr bool hasDefaultRules() const { return args[0].name == nullptr; }
582};
583
587 const char *name;
588 IntrinsicLibrary::Generator generator;
589 // The following may be omitted in the table below.
590 fir::IntrinsicArgumentLoweringRules argLoweringRules = {};
591 bool isElemental = true;
594 bool outline = false;
595};
596
598 // llvm::StringRef comparison operator are not constexpr, so use string_view.
599 using Key = std::string_view;
600 // Needed for implicit compare with keys.
601 constexpr operator Key() const { return key; }
602 Key key; // intrinsic name
603
604 // Name of a runtime function that implements the operation.
605 llvm::StringRef symbol;
606 fir::runtime::FuncTypeBuilderFunc typeGenerator;
607};
608
610 // Callback type for generating lowering for a math operation.
611 using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location,
612 const MathOperation &,
613 mlir::FunctionType,
615
616 // Overrides fir::runtime::FuncTypeBuilderFunc to add FirOpBuilder argument.
617 using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *,
619
620 // llvm::StringRef comparison operator are not constexpr, so use string_view.
621 using Key = std::string_view;
622 // Needed for implicit compare with keys.
623 constexpr operator Key() const { return key; }
624 // Intrinsic name.
625 Key key;
626
627 // Name of a runtime function that implements the operation.
628 llvm::StringRef runtimeFunc;
629 FuncTypeBuilderFunc typeGenerator;
630
631 // A callback to generate FIR for the intrinsic defined by 'key'.
632 // A callback may generate either dedicated MLIR operation(s) or
633 // a function call to a runtime function with name defined by
634 // 'runtimeFunc'.
635 MathGeneratorTy funcGenerator;
636};
637
638// Enum of most supported intrinsic argument or return types.
639enum class ParamTypeId {
640 Void,
641 Address, // pointer (to an [array of] Integers of some kind)
642 Integer,
643 Real,
644 Complex,
645 IntegerVector,
646 UnsignedVector,
647 RealVector,
648};
649
650// Helper function to get length of a 16-byte vector of element type eleTy.
651static int getVecLen(mlir::Type eleTy) {
652 assert((mlir::isa<mlir::IntegerType>(eleTy) ||
653 mlir::isa<mlir::FloatType>(eleTy)) &&
654 "unsupported vector element type");
655 return 16 / (eleTy.getIntOrFloatBitWidth() / 8);
656}
657
658template <ParamTypeId t, int k>
659struct ParamType {
660 // Supported kinds can be checked with static asserts at compile time.
661 static_assert(t != ParamTypeId::Integer || k == 1 || k == 2 || k == 4 ||
662 k == 8,
663 "Unsupported integer kind");
664 static_assert(t != ParamTypeId::Real || k == 4 || k == 8 || k == 10 ||
665 k == 16,
666 "Unsupported real kind");
667 static_assert(t != ParamTypeId::Complex || k == 2 || k == 3 || k == 4 ||
668 k == 8 || k == 10 || k == 16,
669 "Unsupported complex kind");
670
671 static const ParamTypeId ty = t;
672 static const int kind = k;
673};
674
675// Namespace encapsulating type definitions for parameter types.
676namespace Ty {
678template <int k>
680template <int k>
682template <int k>
684template <int k>
686template <int k>
687using IntegerVector = ParamType<ParamTypeId::IntegerVector, k>;
688template <int k>
689using UnsignedVector = ParamType<ParamTypeId::UnsignedVector, k>;
690template <int k>
692} // namespace Ty
693
694// Helper function that generates most types that are supported for intrinsic
695// arguments and return type. Used by `genFuncType` to generate function
696// types for most of the intrinsics.
697static inline mlir::Type getTypeHelper(mlir::MLIRContext *context,
698 fir::FirOpBuilder &builder,
699 ParamTypeId typeId, int kind) {
700 mlir::Type r;
701 unsigned bits{0};
702 switch (typeId) {
703 case ParamTypeId::Void:
704 llvm::report_fatal_error("can not get type of void");
705 break;
706 case ParamTypeId::Address:
707 bits = builder.getKindMap().getIntegerBitsize(kind);
708 assert(bits != 0 && "failed to convert address kind to integer bitsize");
709 r = fir::ReferenceType::get(mlir::IntegerType::get(context, bits));
710 break;
711 case ParamTypeId::Integer:
712 case ParamTypeId::IntegerVector:
713 bits = builder.getKindMap().getIntegerBitsize(kind);
714 assert(bits != 0 && "failed to convert kind to integer bitsize");
715 r = mlir::IntegerType::get(context, bits);
716 break;
717 case ParamTypeId::UnsignedVector:
718 bits = builder.getKindMap().getIntegerBitsize(kind);
719 assert(bits != 0 && "failed to convert kind to unsigned bitsize");
720 r = mlir::IntegerType::get(context, bits, mlir::IntegerType::Unsigned);
721 break;
722 case ParamTypeId::Real:
723 case ParamTypeId::RealVector:
724 r = builder.getRealType(kind);
725 break;
726 case ParamTypeId::Complex:
727 r = mlir::ComplexType::get(builder.getRealType(kind));
728 break;
729 }
730
731 switch (typeId) {
732 case ParamTypeId::Void:
733 case ParamTypeId::Address:
734 case ParamTypeId::Integer:
735 case ParamTypeId::Real:
736 case ParamTypeId::Complex:
737 break;
738 case ParamTypeId::IntegerVector:
739 case ParamTypeId::UnsignedVector:
740 case ParamTypeId::RealVector:
741 // convert to vector type
742 r = fir::VectorType::get(getVecLen(r), r);
743 }
744 return r;
745}
746
747// Generic function type generator that supports most of the function types
748// used by intrinsics.
749template <typename TyR, typename... ArgTys>
750static inline mlir::FunctionType genFuncType(mlir::MLIRContext *context,
751 fir::FirOpBuilder &builder) {
752 llvm::SmallVector<ParamTypeId> argTys = {ArgTys::ty...};
753 llvm::SmallVector<int> argKinds = {ArgTys::kind...};
754 llvm::SmallVector<mlir::Type> argTypes;
755
756 for (size_t i = 0; i < argTys.size(); ++i) {
757 argTypes.push_back(getTypeHelper(context, builder, argTys[i], argKinds[i]));
758 }
759
760 if (TyR::ty == ParamTypeId::Void)
761 return mlir::FunctionType::get(context, argTypes, {});
762
763 auto resType = getTypeHelper(context, builder, TyR::ty, TyR::kind);
764 return mlir::FunctionType::get(context, argTypes, {resType});
765}
766
768struct IntrinsicHandlerEntry {
769 using RuntimeGeneratorRange =
770 std::pair<const MathOperation *, const MathOperation *>;
771 IntrinsicHandlerEntry(const IntrinsicHandler *handler) : entry{handler} {
772 assert(handler && "handler must not be nullptr");
773 };
774 IntrinsicHandlerEntry(RuntimeGeneratorRange rt) : entry{rt} {};
775 const IntrinsicArgumentLoweringRules *getArgumentLoweringRules() const;
776 std::variant<const IntrinsicHandler *, RuntimeGeneratorRange> entry;
777};
778
779//===----------------------------------------------------------------------===//
780// Helper functions for argument handling.
781//===----------------------------------------------------------------------===//
782static inline mlir::Type getConvertedElementType(mlir::MLIRContext *context,
783 mlir::Type eleTy) {
784 if (mlir::isa<mlir::IntegerType>(eleTy) && !eleTy.isSignlessInteger()) {
785 const auto intTy{mlir::dyn_cast<mlir::IntegerType>(eleTy)};
786 auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
787 return newEleTy;
788 }
789 return eleTy;
790}
791
792static inline llvm::SmallVector<mlir::Value, 4>
793getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
794 llvm::SmallVector<mlir::Value, 4> baseVec;
795 for (auto arg : args)
796 baseVec.push_back(getBase(arg));
797 return baseVec;
798}
799
800static inline llvm::SmallVector<mlir::Type, 4>
801getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
802 llvm::SmallVector<mlir::Type, 4> typeVec;
803 for (auto arg : args)
804 typeVec.push_back(arg.getType());
805 return typeVec;
806}
807
808mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
809 const MathOperation &mathOp,
810 mlir::FunctionType libFuncType,
811 llvm::ArrayRef<mlir::Value> args);
812
813template <typename T>
814mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
815 const MathOperation &mathOp,
816 mlir::FunctionType mathLibFuncType,
817 llvm::ArrayRef<mlir::Value> args);
818
819template <typename T>
820mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
821 const MathOperation &mathOp,
822 mlir::FunctionType mathLibFuncType,
823 llvm::ArrayRef<mlir::Value> args);
824
825mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
826 mlir::Location loc,
827 const MathOperation &mathOp,
828 mlir::FunctionType libFuncType,
829 llvm::ArrayRef<mlir::Value> args);
830
833std::optional<IntrinsicHandlerEntry>
834lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName,
835 std::optional<mlir::Type> resultType);
836
838void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name);
839
843getIntrinsicArgumentLowering(llvm::StringRef intrinsicName);
844
848 unsigned position);
849
851fir::ExtendedValue getAbsentIntrinsicArgument();
852
854// implementation) of an unrestricted intrinsic (defined by its signature
855// and generic name)
856mlir::SymbolRefAttr
857getUnrestrictedIntrinsicSymbolRefAttr(fir::FirOpBuilder &, mlir::Location,
858 llvm::StringRef name,
859 mlir::FunctionType signature);
860
861//===----------------------------------------------------------------------===//
862// Direct access to intrinsics that may be used by lowering outside
863// of intrinsic call lowering.
864//===----------------------------------------------------------------------===//
865
868mlir::Value genMax(fir::FirOpBuilder &, mlir::Location,
869 llvm::ArrayRef<mlir::Value> args);
870
872mlir::Value genMin(fir::FirOpBuilder &, mlir::Location,
873 llvm::ArrayRef<mlir::Value> args);
874
877mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
878 mlir::Type resultType, mlir::Value x, mlir::Value y);
879
882mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType,
883 mlir::Value x, mlir::Value y);
884
885} // namespace fir
886
887#endif // FORTRAN_LOWER_INTRINSICCALL_H
Definition AbstractConverter.h:87
Definition BoxValue.h:478
Definition FIRBuilder.h:55
const fir::KindMapping & getKindMap()
Get a reference to the kind map.
Definition FIRBuilder.h:122
mlir::Type getRealType(int kind)
Get the mlir float type that implements Fortran REAL(kind).
Definition FIRBuilder.cpp:119
Bitsize getIntegerBitsize(KindTy kind) const
Get the size in bits of !fir.int<kind>
Definition KindMapping.cpp:283
Definition BoxValue.h:360
Definition FIRType.h:92
Definition ParserActions.h:24
Definition bit-population-count.h:20
Definition AbstractConverter.h:37
std::optional< IntrinsicHandlerEntry > lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName, std::optional< mlir::Type > resultType)
Definition IntrinsicCall.cpp:1887
Extremum
Enums used to templatize and share lowering of MIN and MAX.
Definition IntrinsicCall.h:60
const IntrinsicArgumentLoweringRules * getIntrinsicArgumentLowering(llvm::StringRef intrinsicName)
Definition IntrinsicCall.cpp:9119
mlir::Value getBase(const ExtendedValue &exv)
Definition BoxValue.cpp:21
mlir::Value genMin(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef< mlir::Value > args)
Generate minimum. Same constraints as genMax.
Definition IntrinsicCall.cpp:9176
mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:9189
mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:9184
fir::ExtendedValue getAbsentIntrinsicArgument()
Return place-holder for absent intrinsic arguments.
Definition IntrinsicCall.cpp:80
void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name)
Generate a TODO error message for an as yet unimplemented intrinsic.
Definition IntrinsicCall.cpp:1912
ArgLoweringRule lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &, unsigned position)
Definition IntrinsicCall.cpp:9147
mlir::SymbolRefAttr getUnrestrictedIntrinsicSymbolRefAttr(fir::FirOpBuilder &, mlir::Location, llvm::StringRef name, mlir::FunctionType signature)
Get SymbolRefAttr of runtime (or wrapper function containing inlined.
Definition IntrinsicCall.cpp:9210
LowerIntrinsicArgAs
Definition IntrinsicCall.h:104
@ Addr
Definition IntrinsicCall.h:109
@ Inquired
Definition IntrinsicCall.h:115
@ Box
Lower argument to a box.
Definition IntrinsicCall.h:111
@ Value
Lower argument to a value. Mainly intended for scalar arguments.
Definition IntrinsicCall.h:106
std::pair< fir::ExtendedValue, bool > genIntrinsicCall(fir::FirOpBuilder &, mlir::Location, llvm::StringRef name, std::optional< mlir::Type > resultType, llvm::ArrayRef< fir::ExtendedValue > args, Fortran::lower::AbstractConverter *converter=nullptr)
Definition IntrinsicCall.cpp:9160
mlir::Value genMax(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:9168
Define how a given intrinsic argument must be lowered.
Definition IntrinsicCall.h:119
bool handleDynamicOptional
Value:
Definition IntrinsicCall.h:131
This is shared by intrinsics and intrinsic module procedures.
Definition IntrinsicCall.h:578
IntrinsicDummyArgument args[7]
There is no more than 7 non repeated arguments in Fortran intrinsics.
Definition IntrinsicCall.h:580
Definition IntrinsicCall.h:571
Entry into the tables describing how an intrinsic must be lowered.
Definition IntrinsicCall.h:768
Definition IntrinsicCall.h:586
bool outline
Definition IntrinsicCall.h:594
mlir::SymbolRefAttr getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name, mlir::FunctionType signature)
Definition IntrinsicCall.cpp:2419
fir::ExtendedValue genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType, llvm::ArrayRef< fir::ExtendedValue > args, bool outline)
Generate calls to ElementalGenerator, handling the elemental aspects.
Definition IntrinsicCall.cpp:1924
fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg, mlir::Type resultType, llvm::ArrayRef< fir::ExtendedValue > args)
Process calls to Product, Sum, IAll, IAny, IParity intrinsic functions.
Definition IntrinsicCall.cpp:4486
std::pair< fir::ExtendedValue, bool > genIntrinsicCall(llvm::StringRef name, std::optional< mlir::Type > resultType, llvm::ArrayRef< fir::ExtendedValue > arg)
Definition IntrinsicCall.cpp:2109
decltype(&IntrinsicLibrary::genEtime) DualGenerator
The generator for intrinsic that has both function and subroutine form.
Definition IntrinsicCall.h:504
mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name, mlir::Type resultType, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:2318
mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2490
mlir::Value genQNan(mlir::Type resultType)
Generate a quiet NaN of a given floating point type.
Definition IntrinsicCall.cpp:4699
mlir::Value genConversion(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2498
mlir::Value genAbs(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2512
fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar, llvm::StringRef errMsg, mlir::Type resultType, llvm::ArrayRef< fir::ExtendedValue > args)
Helper for MinVal/MaxVal.
Definition IntrinsicCall.cpp:9028
fir::ExtendedValue readAndAddCleanUp(fir::MutableBoxValue resultMutableBox, mlir::Type resultType, llvm::StringRef errMsg)
Helper function for generating code clean-up for result descriptors.
Definition IntrinsicCall.cpp:2453
decltype(&IntrinsicLibrary::genAbs) ElementalGenerator
Definition IntrinsicCall.h:500
fir::ExtendedValue genCAssociatedCPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_PTR [, C_PTR])
Definition IntrinsicCall.cpp:3160
fir::ExtendedValue genCAssociatedCFunPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_FUNPTR [, C_FUNPTR])
Definition IntrinsicCall.cpp:3153
void genRaiseExcept(int excepts, mlir::Value cond={})
Definition IntrinsicCall.cpp:4706
mlir::Value invokeGenerator(ElementalGenerator generator, mlir::Type resultType, llvm::ArrayRef< mlir::Value > args)
Helper to invoke code generator for the intrinsics given arguments.
Definition IntrinsicCall.cpp:2124
fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg, mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
Process calls to Minloc, Maxloc intrinsic functions.
Definition IntrinsicCall.cpp:8947
Definition IntrinsicCall.h:609
Definition IntrinsicCall.h:659
Definition IntrinsicCall.h:597