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/Lower/AbstractConverter.h"
13#include "flang/Optimizer/Builder/BoxValue.h"
14#include "flang/Optimizer/Builder/FIRBuilder.h"
15#include "flang/Optimizer/Builder/Runtime/Character.h"
16#include "flang/Optimizer/Builder/Runtime/Numeric.h"
18#include "flang/Runtime/entry-names.h"
19#include "flang/Runtime/iostat-consts.h"
20#include "mlir/Dialect/Complex/IR/Complex.h"
21#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
22#include "mlir/Dialect/Math/IR/Math.h"
23#include <optional>
24
25namespace fir {
26
27class StatementContext;
29
35std::pair<fir::ExtendedValue, bool>
36genIntrinsicCall(fir::FirOpBuilder &, mlir::Location, llvm::StringRef name,
37 std::optional<mlir::Type> resultType,
38 llvm::ArrayRef<fir::ExtendedValue> args,
39 Fortran::lower::AbstractConverter *converter = nullptr);
40
44std::pair<fir::ExtendedValue, bool>
45genIntrinsicCall(fir::FirOpBuilder &, mlir::Location,
47 std::optional<mlir::Type> resultType,
48 llvm::ArrayRef<fir::ExtendedValue> args,
49 Fortran::lower::AbstractConverter *converter = nullptr);
50
52enum class Extremum { Min, Max };
53
54// There are different ways to deal with NaNs in MIN and MAX.
55// Known existing behaviors are listed below and can be selected for
56// f18 MIN/MAX implementation.
57enum class ExtremumBehavior {
58 // Note: the Signaling/quiet aspect of NaNs in the behaviors below are
59 // not described because there is no way to control/observe such aspect in
60 // MLIR/LLVM yet. The IEEE behaviors come with requirements regarding this
61 // aspect that are therefore currently not enforced. In the descriptions
62 // below, NaNs can be signaling or quite. Returned NaNs may be signaling
63 // if one of the input NaN was signaling but it cannot be guaranteed either.
64 // Existing compilers using an IEEE behavior (gfortran) also do not fulfill
65 // signaling/quiet requirements.
66 IeeeMinMaximumNumber,
67 // IEEE minimumNumber/maximumNumber behavior (754-2019, section 9.6):
68 // If one of the argument is and number and the other is NaN, return the
69 // number. If both arguements are NaN, return NaN.
70 // Compilers: gfortran.
71 IeeeMinMaximum,
72 // IEEE minimum/maximum behavior (754-2019, section 9.6):
73 // If one of the argument is NaN, return NaN.
74 MinMaxss,
75 // x86 minss/maxss behavior:
76 // If the second argument is a number and the other is NaN, return the number.
77 // In all other cases where at least one operand is NaN, return NaN.
78 // Compilers: xlf (only for MAX), ifort, pgfortran -nollvm, and nagfor.
79 PgfortranLlvm,
80 // "Opposite of" x86 minss/maxss behavior:
81 // If the first argument is a number and the other is NaN, return the
82 // number.
83 // In all other cases where at least one operand is NaN, return NaN.
84 // Compilers: xlf (only for MIN), and pgfortran (with llvm).
85 IeeeMinMaxNum
86 // IEEE minNum/maxNum behavior (754-2008, section 5.3.1):
87 // TODO: Not implemented.
88 // It is the only behavior where the signaling/quiet aspect of a NaN argument
89 // impacts if the result should be NaN or the argument that is a number.
90 // LLVM/MLIR do not provide ways to observe this aspect, so it is not
91 // possible to implement it without some target dependent runtime.
92};
93
109
112 LowerIntrinsicArgAs lowerAs;
114 // - Numerical: 0
115 // - Logical : false
116 // - Derived/character: not possible. Need custom intrinsic lowering.
117 // Addr:
118 // - nullptr
119 // Box:
120 // - absent box
121 // AsInquired:
122 // - no-op
124};
125
126constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
127constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
128constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
129constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired;
130
134
135// TODO error handling -> return a code or directly emit messages ?
136struct IntrinsicLibrary {
137
138 // Constructors.
139 explicit IntrinsicLibrary(
140 fir::FirOpBuilder &builder, mlir::Location loc,
141 Fortran::lower::AbstractConverter *converter = nullptr)
142 : builder{builder}, loc{loc}, converter{converter} {}
143 IntrinsicLibrary() = delete;
144 IntrinsicLibrary(const IntrinsicLibrary &) = delete;
145
149 std::pair<fir::ExtendedValue, bool>
150 genIntrinsicCall(llvm::StringRef name, std::optional<mlir::Type> resultType,
152
160 mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type,
162
163 using RuntimeCallGenerator = std::function<mlir::Value(
165 RuntimeCallGenerator
166 getRuntimeCallGenerator(llvm::StringRef name,
167 mlir::FunctionType soughtFuncType);
168
174 mlir::Value genAbs(mlir::Type, llvm::ArrayRef<mlir::Value>);
175 mlir::Value genAcosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
176 mlir::Value genAcospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
177 template <void (*CallRuntime)(fir::FirOpBuilder &, mlir::Location loc,
178 mlir::Value, mlir::Value)>
179 fir::ExtendedValue genAdjustRtCall(mlir::Type,
181 mlir::Value genAimag(mlir::Type, llvm::ArrayRef<mlir::Value>);
182 mlir::Value genAint(mlir::Type, llvm::ArrayRef<mlir::Value>);
184 fir::ExtendedValue genAllocated(mlir::Type,
186 mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
188 mlir::Value genAtanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
190 genCommandArgumentCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
191 mlir::Value genAsind(mlir::Type, llvm::ArrayRef<mlir::Value>);
192 mlir::Value genAsinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
193 fir::ExtendedValue genAssociated(mlir::Type,
195 mlir::Value genAtand(mlir::Type, llvm::ArrayRef<mlir::Value>);
196 fir::ExtendedValue genBesselJn(mlir::Type,
198 fir::ExtendedValue genBesselYn(mlir::Type,
200 template <mlir::arith::CmpIPredicate pred>
201 mlir::Value genBitwiseCompare(mlir::Type resultType,
203
204 mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
205 mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
207 fir::ExtendedValue genChdir(std::optional<mlir::Type> resultType,
209 template <mlir::arith::CmpIPredicate pred>
210 fir::ExtendedValue genCharacterCompare(mlir::Type,
212 mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
213 mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
215 void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
222 mlir::Value genErfcScaled(mlir::Type resultType,
224 void genCFPointer(llvm::ArrayRef<fir::ExtendedValue>);
225 void genCFProcPointer(llvm::ArrayRef<fir::ExtendedValue>);
228 template <mlir::arith::CmpIPredicate pred>
229 fir::ExtendedValue genCPtrCompare(mlir::Type,
231 void genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue>);
235 mlir::Value genCosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
236 mlir::Value genCospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
237 void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
238 fir::ExtendedValue genDsecnds(mlir::Type resultType,
240 mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
241 fir::ExtendedValue genDotProduct(mlir::Type,
243 mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
244 mlir::Value genDshiftl(mlir::Type, llvm::ArrayRef<mlir::Value>);
245 mlir::Value genDshiftr(mlir::Type, llvm::ArrayRef<mlir::Value>);
248 void genExecuteCommandLine(mlir::ArrayRef<fir::ExtendedValue> args);
249 fir::ExtendedValue genEtime(std::optional<mlir::Type>,
250 mlir::ArrayRef<fir::ExtendedValue> args);
251 mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
252 fir::ExtendedValue genExtendsTypeOf(mlir::Type,
254 template <Extremum, ExtremumBehavior>
255 mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
256 mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
258 mlir::Value genFraction(mlir::Type resultType,
259 mlir::ArrayRef<mlir::Value> args);
260 void genFree(mlir::ArrayRef<fir::ExtendedValue> args);
261 fir::ExtendedValue genFseek(std::optional<mlir::Type>,
262 mlir::ArrayRef<fir::ExtendedValue> args);
263 fir::ExtendedValue genFtell(std::optional<mlir::Type>,
264 mlir::ArrayRef<fir::ExtendedValue> args);
265 fir::ExtendedValue genGetCwd(std::optional<mlir::Type> resultType,
267 void genGetCommand(mlir::ArrayRef<fir::ExtendedValue> args);
268 mlir::Value genGetPID(mlir::Type resultType,
270 void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
271 void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
272 mlir::Value genGetGID(mlir::Type resultType,
274 mlir::Value genGetTeam(mlir::Type, llvm::ArrayRef<mlir::Value>);
275 mlir::Value genGetUID(mlir::Type resultType,
277 fir::ExtendedValue genHostnm(std::optional<mlir::Type> resultType,
280 mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
282 mlir::Value genIbclr(mlir::Type, llvm::ArrayRef<mlir::Value>);
283 mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
284 mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
287 mlir::Value genIeeeClass(mlir::Type, llvm::ArrayRef<mlir::Value>);
288 mlir::Value genIeeeCopySign(mlir::Type, llvm::ArrayRef<mlir::Value>);
289 void genIeeeGetFlag(llvm::ArrayRef<fir::ExtendedValue>);
290 void genIeeeGetHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
291 template <bool isGet, bool isModes>
292 void genIeeeGetOrSetModesOrStatus(llvm::ArrayRef<fir::ExtendedValue>);
293 void genIeeeGetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
294 void genIeeeGetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
295 mlir::Value genIeeeInt(mlir::Type, llvm::ArrayRef<mlir::Value>);
296 mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
297 mlir::Value genIeeeIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
298 mlir::Value genIeeeIsNegative(mlir::Type, llvm::ArrayRef<mlir::Value>);
299 mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef<mlir::Value>);
300 mlir::Value genIeeeLogb(mlir::Type, mlir::ArrayRef<mlir::Value>);
301 template <bool isMax, bool isNum, bool isMag>
302 mlir::Value genIeeeMaxMin(mlir::Type, llvm::ArrayRef<mlir::Value>);
303 template <mlir::arith::CmpFPredicate pred>
304 mlir::Value genIeeeQuietCompare(mlir::Type resultType,
306 mlir::Value genIeeeReal(mlir::Type, llvm::ArrayRef<mlir::Value>);
307 mlir::Value genIeeeRem(mlir::Type, llvm::ArrayRef<mlir::Value>);
308 mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
309 template <bool isFlag>
310 void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
311 void genIeeeSetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
312 void genIeeeSetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
313 template <mlir::arith::CmpFPredicate pred>
314 mlir::Value genIeeeSignalingCompare(mlir::Type resultType,
316 mlir::Value genIeeeSignbit(mlir::Type, llvm::ArrayRef<mlir::Value>);
317 fir::ExtendedValue genIeeeSupportFlag(mlir::Type,
319 fir::ExtendedValue genIeeeSupportHalting(mlir::Type,
321 fir::ExtendedValue genIeeeSupportRounding(mlir::Type,
323 fir::ExtendedValue genIeeeSupportStandard(mlir::Type,
325 template <mlir::arith::CmpIPredicate pred>
326 mlir::Value genIeeeTypeCompare(mlir::Type, llvm::ArrayRef<mlir::Value>);
327 mlir::Value genIeeeUnordered(mlir::Type, llvm::ArrayRef<mlir::Value>);
328 mlir::Value genIeeeValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
329 mlir::Value genIeor(mlir::Type, llvm::ArrayRef<mlir::Value>);
331 mlir::Value genIor(mlir::Type, llvm::ArrayRef<mlir::Value>);
333 fir::ExtendedValue genIrand(mlir::Type resultType,
335 fir::ExtendedValue genIsContiguous(mlir::Type,
337 template <Fortran::runtime::io::Iostat value>
338 mlir::Value genIsIostatValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
339 mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef<mlir::Value>,
340 int fpclass);
341 mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
342 mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
344 mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
348 mlir::Value genMalloc(mlir::Type, llvm::ArrayRef<mlir::Value>);
349 template <typename Shift>
350 mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
352 fir::ExtendedValue genMatmulTranspose(mlir::Type,
357 mlir::Value genMergeBits(mlir::Type, llvm::ArrayRef<mlir::Value>);
360 mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
361 mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
362 void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
364 enum class NearestProc { Nearest, NextAfter, NextDown, NextUp };
365 template <NearestProc>
366 mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
367 mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
369 mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
371 fir::ExtendedValue genNumImages(mlir::Type,
376 mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
377 mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
380 fir::ExtendedValue genPutenv(std::optional<mlir::Type>,
382 fir::ExtendedValue genRand(mlir::Type resultType,
384 void genRandomInit(llvm::ArrayRef<fir::ExtendedValue>);
385 void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
386 void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
388 fir::ExtendedValue genReduceDim(mlir::Type,
390 fir::ExtendedValue genRename(std::optional<mlir::Type>,
391 mlir::ArrayRef<fir::ExtendedValue>);
394 mlir::Value genRRSpacing(mlir::Type resultType,
396 fir::ExtendedValue genSameTypeAs(mlir::Type,
398 mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
400 fir::ExtendedValue genSecnds(mlir::Type resultType,
402 fir::ExtendedValue genSecond(std::optional<mlir::Type>,
403 mlir::ArrayRef<fir::ExtendedValue>);
404 fir::ExtendedValue genSelectedCharKind(mlir::Type,
406 mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
407 mlir::Value genSelectedLogicalKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
408 mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
409 mlir::Value genSetExponent(mlir::Type resultType,
411 fir::ExtendedValue genShape(mlir::Type resultType,
413 template <typename Shift>
414 mlir::Value genShift(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
415 mlir::Value genShiftA(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
416 void genShowDescriptor(llvm::ArrayRef<fir::ExtendedValue>);
417 mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
418 mlir::Value genSind(mlir::Type, llvm::ArrayRef<mlir::Value>);
419 mlir::Value genSinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
422 mlir::Value genSpacing(mlir::Type resultType,
425 fir::ExtendedValue genStorageSize(mlir::Type,
428 void genSignalSubroutine(llvm::ArrayRef<fir::ExtendedValue>);
430 fir::ExtendedValue genSystem(std::optional<mlir::Type>,
431 mlir::ArrayRef<fir::ExtendedValue> args);
432 void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
433 mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
434 mlir::Value genTanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
435 fir::ExtendedValue genTeamNumber(mlir::Type,
437 mlir::Value genTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
438 mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
439 fir::ExtendedValue genTransfer(mlir::Type,
441 fir::ExtendedValue genTranspose(mlir::Type,
443 fir::ExtendedValue genThisImage(mlir::Type,
447 fir::ExtendedValue genUnlink(std::optional<mlir::Type> resultType,
451
455 mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
456
462 template <typename FN, typename FD>
463 fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg,
464 mlir::Type,
466 template <typename FN, typename FD, typename FC>
468 fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar,
469 llvm::StringRef errMsg,
470 mlir::Type resultType,
473 template <typename FN, typename FD>
474 fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg,
475 mlir::Type resultType,
477
480 void genRaiseExcept(int excepts, mlir::Value cond = {});
481
483 mlir::Value genQNan(mlir::Type resultType);
484
488 using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
489 using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
491 using DualGenerator = decltype(&IntrinsicLibrary::genEtime);
492 using Generator = std::variant<ElementalGenerator, ExtendedGenerator,
493 SubroutineGenerator, DualGenerator>;
494
501 template <typename GeneratorType>
502 mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name,
503 mlir::Type resultType,
505 template <typename GeneratorType>
507 outlineInExtendedWrapper(GeneratorType, llvm::StringRef name,
508 std::optional<mlir::Type> resultType,
510
511 template <typename GeneratorType>
512 mlir::func::FuncOp getWrapper(GeneratorType, llvm::StringRef name,
513 mlir::FunctionType,
514 bool loadRefArguments = false);
515
517 template <typename GeneratorType>
519 genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType,
520 llvm::ArrayRef<fir::ExtendedValue> args, bool outline);
521
523 mlir::Value invokeGenerator(ElementalGenerator generator,
524 mlir::Type resultType,
526 mlir::Value invokeGenerator(RuntimeCallGenerator generator,
527 mlir::Type resultType,
529 mlir::Value invokeGenerator(ExtendedGenerator generator,
530 mlir::Type resultType,
532 mlir::Value invokeGenerator(SubroutineGenerator generator,
534 mlir::Value invokeGenerator(DualGenerator generator,
536 mlir::Value invokeGenerator(DualGenerator generator, mlir::Type resultType,
538
541 mlir::SymbolRefAttr
542 getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name,
543 mlir::FunctionType signature);
544
547 mlir::Type resultType,
548 llvm::StringRef errMsg);
549
550 void setResultMustBeFreed() { resultMustBeFreed = true; }
551
552 fir::FirOpBuilder &builder;
553 mlir::Location loc;
554 bool resultMustBeFreed = false;
555 Fortran::lower::AbstractConverter *converter = nullptr;
556};
557
559 const char *name = nullptr;
561 bool handleDynamicOptional = false;
562};
563
568 constexpr bool hasDefaultRules() const { return args[0].name == nullptr; }
569};
570
574 const char *name;
575 IntrinsicLibrary::Generator generator;
576 // The following may be omitted in the table below.
577 fir::IntrinsicArgumentLoweringRules argLoweringRules = {};
578 bool isElemental = true;
581 bool outline = false;
582};
583
585 // llvm::StringRef comparison operator are not constexpr, so use string_view.
586 using Key = std::string_view;
587 // Needed for implicit compare with keys.
588 constexpr operator Key() const { return key; }
589 Key key; // intrinsic name
590
591 // Name of a runtime function that implements the operation.
592 llvm::StringRef symbol;
593 fir::runtime::FuncTypeBuilderFunc typeGenerator;
594};
595
597 // Callback type for generating lowering for a math operation.
598 using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location,
599 const MathOperation &,
600 mlir::FunctionType,
602
603 // Overrides fir::runtime::FuncTypeBuilderFunc to add FirOpBuilder argument.
604 using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *,
606
607 // llvm::StringRef comparison operator are not constexpr, so use string_view.
608 using Key = std::string_view;
609 // Needed for implicit compare with keys.
610 constexpr operator Key() const { return key; }
611 // Intrinsic name.
612 Key key;
613
614 // Name of a runtime function that implements the operation.
615 llvm::StringRef runtimeFunc;
616 FuncTypeBuilderFunc typeGenerator;
617
618 // A callback to generate FIR for the intrinsic defined by 'key'.
619 // A callback may generate either dedicated MLIR operation(s) or
620 // a function call to a runtime function with name defined by
621 // 'runtimeFunc'.
622 MathGeneratorTy funcGenerator;
623};
624
625// Enum of most supported intrinsic argument or return types.
626enum class ParamTypeId {
627 Void,
628 Address, // pointer (to an [array of] Integers of some kind)
629 Integer,
630 Real,
631 Complex,
632 IntegerVector,
633 UnsignedVector,
634 RealVector,
635};
636
637// Helper function to get length of a 16-byte vector of element type eleTy.
638static int getVecLen(mlir::Type eleTy) {
639 assert((mlir::isa<mlir::IntegerType>(eleTy) ||
640 mlir::isa<mlir::FloatType>(eleTy)) &&
641 "unsupported vector element type");
642 return 16 / (eleTy.getIntOrFloatBitWidth() / 8);
643}
644
645template <ParamTypeId t, int k>
646struct ParamType {
647 // Supported kinds can be checked with static asserts at compile time.
648 static_assert(t != ParamTypeId::Integer || k == 1 || k == 2 || k == 4 ||
649 k == 8,
650 "Unsupported integer kind");
651 static_assert(t != ParamTypeId::Real || k == 4 || k == 8 || k == 10 ||
652 k == 16,
653 "Unsupported real kind");
654 static_assert(t != ParamTypeId::Complex || k == 2 || k == 3 || k == 4 ||
655 k == 8 || k == 10 || k == 16,
656 "Unsupported complex kind");
657
658 static const ParamTypeId ty = t;
659 static const int kind = k;
660};
661
662// Namespace encapsulating type definitions for parameter types.
663namespace Ty {
665template <int k>
667template <int k>
669template <int k>
671template <int k>
673template <int k>
674using IntegerVector = ParamType<ParamTypeId::IntegerVector, k>;
675template <int k>
676using UnsignedVector = ParamType<ParamTypeId::UnsignedVector, k>;
677template <int k>
679} // namespace Ty
680
681// Helper function that generates most types that are supported for intrinsic
682// arguments and return type. Used by `genFuncType` to generate function
683// types for most of the intrinsics.
684static inline mlir::Type getTypeHelper(mlir::MLIRContext *context,
685 fir::FirOpBuilder &builder,
686 ParamTypeId typeId, int kind) {
687 mlir::Type r;
688 unsigned bits{0};
689 switch (typeId) {
690 case ParamTypeId::Void:
691 llvm::report_fatal_error("can not get type of void");
692 break;
693 case ParamTypeId::Address:
694 bits = builder.getKindMap().getIntegerBitsize(kind);
695 assert(bits != 0 && "failed to convert address kind to integer bitsize");
696 r = fir::ReferenceType::get(mlir::IntegerType::get(context, bits));
697 break;
698 case ParamTypeId::Integer:
699 case ParamTypeId::IntegerVector:
700 bits = builder.getKindMap().getIntegerBitsize(kind);
701 assert(bits != 0 && "failed to convert kind to integer bitsize");
702 r = mlir::IntegerType::get(context, bits);
703 break;
704 case ParamTypeId::UnsignedVector:
705 bits = builder.getKindMap().getIntegerBitsize(kind);
706 assert(bits != 0 && "failed to convert kind to unsigned bitsize");
707 r = mlir::IntegerType::get(context, bits, mlir::IntegerType::Unsigned);
708 break;
709 case ParamTypeId::Real:
710 case ParamTypeId::RealVector:
711 r = builder.getRealType(kind);
712 break;
713 case ParamTypeId::Complex:
714 r = mlir::ComplexType::get(builder.getRealType(kind));
715 break;
716 }
717
718 switch (typeId) {
719 case ParamTypeId::Void:
720 case ParamTypeId::Address:
721 case ParamTypeId::Integer:
722 case ParamTypeId::Real:
723 case ParamTypeId::Complex:
724 break;
725 case ParamTypeId::IntegerVector:
726 case ParamTypeId::UnsignedVector:
727 case ParamTypeId::RealVector:
728 // convert to vector type
729 r = fir::VectorType::get(getVecLen(r), r);
730 }
731 return r;
732}
733
734// Generic function type generator that supports most of the function types
735// used by intrinsics.
736template <typename TyR, typename... ArgTys>
737static inline mlir::FunctionType genFuncType(mlir::MLIRContext *context,
738 fir::FirOpBuilder &builder) {
739 llvm::SmallVector<ParamTypeId> argTys = {ArgTys::ty...};
740 llvm::SmallVector<int> argKinds = {ArgTys::kind...};
741 llvm::SmallVector<mlir::Type> argTypes;
742
743 for (size_t i = 0; i < argTys.size(); ++i) {
744 argTypes.push_back(getTypeHelper(context, builder, argTys[i], argKinds[i]));
745 }
746
747 if (TyR::ty == ParamTypeId::Void)
748 return mlir::FunctionType::get(context, argTypes, {});
749
750 auto resType = getTypeHelper(context, builder, TyR::ty, TyR::kind);
751 return mlir::FunctionType::get(context, argTypes, {resType});
752}
753
755struct IntrinsicHandlerEntry {
756 using RuntimeGeneratorRange =
757 std::pair<const MathOperation *, const MathOperation *>;
758 IntrinsicHandlerEntry(const IntrinsicHandler *handler) : entry{handler} {
759 assert(handler && "handler must not be nullptr");
760 };
761 IntrinsicHandlerEntry(RuntimeGeneratorRange rt) : entry{rt} {};
762 const IntrinsicArgumentLoweringRules *getArgumentLoweringRules() const;
763 std::variant<const IntrinsicHandler *, RuntimeGeneratorRange> entry;
764};
765
766//===----------------------------------------------------------------------===//
767// Helper functions for argument handling.
768//===----------------------------------------------------------------------===//
769static inline mlir::Type getConvertedElementType(mlir::MLIRContext *context,
770 mlir::Type eleTy) {
771 if (mlir::isa<mlir::IntegerType>(eleTy) && !eleTy.isSignlessInteger()) {
772 const auto intTy{mlir::dyn_cast<mlir::IntegerType>(eleTy)};
773 auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
774 return newEleTy;
775 }
776 return eleTy;
777}
778
779static inline llvm::SmallVector<mlir::Value, 4>
780getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
781 llvm::SmallVector<mlir::Value, 4> baseVec;
782 for (auto arg : args)
783 baseVec.push_back(getBase(arg));
784 return baseVec;
785}
786
787static inline llvm::SmallVector<mlir::Type, 4>
788getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
789 llvm::SmallVector<mlir::Type, 4> typeVec;
790 for (auto arg : args)
791 typeVec.push_back(arg.getType());
792 return typeVec;
793}
794
795mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
796 const MathOperation &mathOp,
797 mlir::FunctionType libFuncType,
798 llvm::ArrayRef<mlir::Value> args);
799
800template <typename T>
801mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
802 const MathOperation &mathOp,
803 mlir::FunctionType mathLibFuncType,
804 llvm::ArrayRef<mlir::Value> args);
805
806template <typename T>
807mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
808 const MathOperation &mathOp,
809 mlir::FunctionType mathLibFuncType,
810 llvm::ArrayRef<mlir::Value> args);
811
812mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
813 mlir::Location loc,
814 const MathOperation &mathOp,
815 mlir::FunctionType libFuncType,
816 llvm::ArrayRef<mlir::Value> args);
817
820std::optional<IntrinsicHandlerEntry>
821lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName,
822 std::optional<mlir::Type> resultType);
823
825void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name);
826
830getIntrinsicArgumentLowering(llvm::StringRef intrinsicName);
831
835 unsigned position);
836
838fir::ExtendedValue getAbsentIntrinsicArgument();
839
841// implementation) of an unrestricted intrinsic (defined by its signature
842// and generic name)
843mlir::SymbolRefAttr
844getUnrestrictedIntrinsicSymbolRefAttr(fir::FirOpBuilder &, mlir::Location,
845 llvm::StringRef name,
846 mlir::FunctionType signature);
847
848//===----------------------------------------------------------------------===//
849// Direct access to intrinsics that may be used by lowering outside
850// of intrinsic call lowering.
851//===----------------------------------------------------------------------===//
852
855mlir::Value genMax(fir::FirOpBuilder &, mlir::Location,
856 llvm::ArrayRef<mlir::Value> args);
857
859mlir::Value genMin(fir::FirOpBuilder &, mlir::Location,
860 llvm::ArrayRef<mlir::Value> args);
861
864mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
865 mlir::Type resultType, mlir::Value x, mlir::Value y);
866
869mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType,
870 mlir::Value x, mlir::Value y);
871
872} // namespace fir
873
874#endif // FORTRAN_LOWER_INTRINSICCALL_H
Definition AbstractConverter.h:85
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:118
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 AbstractConverter.h:34
std::optional< IntrinsicHandlerEntry > lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName, std::optional< mlir::Type > resultType)
Definition IntrinsicCall.cpp:1868
Extremum
Enums used to templatize and share lowering of MIN and MAX.
Definition IntrinsicCall.h:52
const IntrinsicArgumentLoweringRules * getIntrinsicArgumentLowering(llvm::StringRef intrinsicName)
Definition IntrinsicCall.cpp:8848
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:8905
mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:8918
mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:8913
fir::ExtendedValue getAbsentIntrinsicArgument()
Return place-holder for absent intrinsic arguments.
Definition IntrinsicCall.cpp:79
void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name)
Generate a TODO error message for an as yet unimplemented intrinsic.
Definition IntrinsicCall.cpp:1893
ArgLoweringRule lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &, unsigned position)
Definition IntrinsicCall.cpp:8876
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:8939
LowerIntrinsicArgAs
Definition IntrinsicCall.h:96
@ Addr
Definition IntrinsicCall.h:101
@ Inquired
Definition IntrinsicCall.h:107
@ Box
Lower argument to a box.
Definition IntrinsicCall.h:103
@ Value
Lower argument to a value. Mainly intended for scalar arguments.
Definition IntrinsicCall.h:98
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:8889
mlir::Value genMax(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:8897
Define how a given intrinsic argument must be lowered.
Definition IntrinsicCall.h:111
bool handleDynamicOptional
Value:
Definition IntrinsicCall.h:123
This is shared by intrinsics and intrinsic module procedures.
Definition IntrinsicCall.h:565
IntrinsicDummyArgument args[7]
There is no more than 7 non repeated arguments in Fortran intrinsics.
Definition IntrinsicCall.h:567
Definition IntrinsicCall.h:558
Entry into the tables describing how an intrinsic must be lowered.
Definition IntrinsicCall.h:755
Definition IntrinsicCall.h:573
bool outline
Definition IntrinsicCall.h:581
mlir::SymbolRefAttr getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name, mlir::FunctionType signature)
Definition IntrinsicCall.cpp:2400
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:1905
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:4351
std::pair< fir::ExtendedValue, bool > genIntrinsicCall(llvm::StringRef name, std::optional< mlir::Type > resultType, llvm::ArrayRef< fir::ExtendedValue > arg)
Definition IntrinsicCall.cpp:2090
decltype(&IntrinsicLibrary::genEtime) DualGenerator
The generator for intrinsic that has both function and subroutine form.
Definition IntrinsicCall.h:491
mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name, mlir::Type resultType, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:2299
mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2471
mlir::Value genQNan(mlir::Type resultType)
Generate a quiet NaN of a given floating point type.
Definition IntrinsicCall.cpp:4564
mlir::Value genConversion(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2479
mlir::Value genAbs(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2493
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:8757
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:2434
decltype(&IntrinsicLibrary::genAbs) ElementalGenerator
Definition IntrinsicCall.h:487
fir::ExtendedValue genCAssociatedCPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_PTR [, C_PTR])
Definition IntrinsicCall.cpp:3141
fir::ExtendedValue genCAssociatedCFunPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_FUNPTR [, C_FUNPTR])
Definition IntrinsicCall.cpp:3134
void genRaiseExcept(int excepts, mlir::Value cond={})
Definition IntrinsicCall.cpp:4571
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:2105
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:8676
Definition IntrinsicCall.h:596
Definition IntrinsicCall.h:646
Definition IntrinsicCall.h:584