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/LLVMIR/NVVMDialect.h"
23#include "mlir/Dialect/Math/IR/Math.h"
24#include <optional>
25
26namespace fir {
27
28class StatementContext;
30
36std::pair<fir::ExtendedValue, bool>
37genIntrinsicCall(fir::FirOpBuilder &, mlir::Location, llvm::StringRef name,
38 std::optional<mlir::Type> resultType,
39 llvm::ArrayRef<fir::ExtendedValue> args,
40 Fortran::lower::AbstractConverter *converter = nullptr);
41
45std::pair<fir::ExtendedValue, bool>
46genIntrinsicCall(fir::FirOpBuilder &, mlir::Location,
48 std::optional<mlir::Type> resultType,
49 llvm::ArrayRef<fir::ExtendedValue> args,
50 Fortran::lower::AbstractConverter *converter = nullptr);
51
53enum class Extremum { Min, Max };
54
55// There are different ways to deal with NaNs in MIN and MAX.
56// Known existing behaviors are listed below and can be selected for
57// f18 MIN/MAX implementation.
58enum class ExtremumBehavior {
59 // Note: the Signaling/quiet aspect of NaNs in the behaviors below are
60 // not described because there is no way to control/observe such aspect in
61 // MLIR/LLVM yet. The IEEE behaviors come with requirements regarding this
62 // aspect that are therefore currently not enforced. In the descriptions
63 // below, NaNs can be signaling or quite. Returned NaNs may be signaling
64 // if one of the input NaN was signaling but it cannot be guaranteed either.
65 // Existing compilers using an IEEE behavior (gfortran) also do not fulfill
66 // signaling/quiet requirements.
67 IeeeMinMaximumNumber,
68 // IEEE minimumNumber/maximumNumber behavior (754-2019, section 9.6):
69 // If one of the argument is and number and the other is NaN, return the
70 // number. If both arguements are NaN, return NaN.
71 // Compilers: gfortran.
72 IeeeMinMaximum,
73 // IEEE minimum/maximum behavior (754-2019, section 9.6):
74 // If one of the argument is NaN, return NaN.
75 MinMaxss,
76 // x86 minss/maxss behavior:
77 // If the second argument is a number and the other is NaN, return the number.
78 // In all other cases where at least one operand is NaN, return NaN.
79 // Compilers: xlf (only for MAX), ifort, pgfortran -nollvm, and nagfor.
80 PgfortranLlvm,
81 // "Opposite of" x86 minss/maxss behavior:
82 // If the first argument is a number and the other is NaN, return the
83 // number.
84 // In all other cases where at least one operand is NaN, return NaN.
85 // Compilers: xlf (only for MIN), and pgfortran (with llvm).
86 IeeeMinMaxNum
87 // IEEE minNum/maxNum behavior (754-2008, section 5.3.1):
88 // TODO: Not implemented.
89 // It is the only behavior where the signaling/quiet aspect of a NaN argument
90 // impacts if the result should be NaN or the argument that is a number.
91 // LLVM/MLIR do not provide ways to observe this aspect, so it is not
92 // possible to implement it without some target dependent runtime.
93};
94
110
113 LowerIntrinsicArgAs lowerAs;
115 // - Numerical: 0
116 // - Logical : false
117 // - Derived/character: not possible. Need custom intrinsic lowering.
118 // Addr:
119 // - nullptr
120 // Box:
121 // - absent box
122 // AsInquired:
123 // - no-op
125};
126
127constexpr auto asValue = fir::LowerIntrinsicArgAs::Value;
128constexpr auto asAddr = fir::LowerIntrinsicArgAs::Addr;
129constexpr auto asBox = fir::LowerIntrinsicArgAs::Box;
130constexpr auto asInquired = fir::LowerIntrinsicArgAs::Inquired;
131
135
136// TODO error handling -> return a code or directly emit messages ?
137struct IntrinsicLibrary {
138
139 // Constructors.
140 explicit IntrinsicLibrary(
141 fir::FirOpBuilder &builder, mlir::Location loc,
142 Fortran::lower::AbstractConverter *converter = nullptr)
143 : builder{builder}, loc{loc}, converter{converter} {}
144 IntrinsicLibrary() = delete;
145 IntrinsicLibrary(const IntrinsicLibrary &) = delete;
146
150 std::pair<fir::ExtendedValue, bool>
151 genIntrinsicCall(llvm::StringRef name, std::optional<mlir::Type> resultType,
153
161 mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type,
163
164 using RuntimeCallGenerator = std::function<mlir::Value(
166 RuntimeCallGenerator
167 getRuntimeCallGenerator(llvm::StringRef name,
168 mlir::FunctionType soughtFuncType);
169
175 mlir::Value genAbs(mlir::Type, llvm::ArrayRef<mlir::Value>);
176 mlir::Value genAcosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
177 mlir::Value genAcospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
178 template <void (*CallRuntime)(fir::FirOpBuilder &, mlir::Location loc,
179 mlir::Value, mlir::Value)>
180 fir::ExtendedValue genAdjustRtCall(mlir::Type,
182 mlir::Value genAimag(mlir::Type, llvm::ArrayRef<mlir::Value>);
183 mlir::Value genAint(mlir::Type, llvm::ArrayRef<mlir::Value>);
185 fir::ExtendedValue genAllocated(mlir::Type,
187 mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
189 mlir::Value genAtanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
190 mlir::Value genAtomicAdd(mlir::Type, llvm::ArrayRef<mlir::Value>);
191 mlir::Value genAtomicAnd(mlir::Type, llvm::ArrayRef<mlir::Value>);
192 fir::ExtendedValue genAtomicCas(mlir::Type,
194 mlir::Value genAtomicDec(mlir::Type, llvm::ArrayRef<mlir::Value>);
195 fir::ExtendedValue genAtomicExch(mlir::Type,
197 mlir::Value genAtomicInc(mlir::Type, llvm::ArrayRef<mlir::Value>);
198 mlir::Value genAtomicMax(mlir::Type, llvm::ArrayRef<mlir::Value>);
199 mlir::Value genAtomicMin(mlir::Type, llvm::ArrayRef<mlir::Value>);
200 mlir::Value genAtomicOr(mlir::Type, llvm::ArrayRef<mlir::Value>);
201 mlir::Value genAtomicSub(mlir::Type, llvm::ArrayRef<mlir::Value>);
202 fir::ExtendedValue genAtomicXor(mlir::Type,
205 genCommandArgumentCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
206 mlir::Value genAsind(mlir::Type, llvm::ArrayRef<mlir::Value>);
207 mlir::Value genAsinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
208 fir::ExtendedValue genAssociated(mlir::Type,
210 mlir::Value genAtand(mlir::Type, llvm::ArrayRef<mlir::Value>);
211 fir::ExtendedValue genBesselJn(mlir::Type,
213 fir::ExtendedValue genBesselYn(mlir::Type,
215 template <mlir::arith::CmpIPredicate pred>
216 mlir::Value genBitwiseCompare(mlir::Type resultType,
218
219 mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
220 mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
222 fir::ExtendedValue genChdir(std::optional<mlir::Type> resultType,
224 template <mlir::arith::CmpIPredicate pred>
225 fir::ExtendedValue genCharacterCompare(mlir::Type,
227 mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
228 mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
230 void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
232 template <const char *fctName, int extent>
233 fir::ExtendedValue genCUDALDXXFunc(mlir::Type,
240 mlir::Value genErfcScaled(mlir::Type resultType,
242 void genCFPointer(llvm::ArrayRef<fir::ExtendedValue>);
243 void genCFProcPointer(llvm::ArrayRef<fir::ExtendedValue>);
246 template <mlir::arith::CmpIPredicate pred>
247 fir::ExtendedValue genCPtrCompare(mlir::Type,
249 void genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue>);
253 mlir::Value genCosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
254 mlir::Value genCospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
255 void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
256 fir::ExtendedValue genDsecnds(mlir::Type resultType,
258 mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
259 fir::ExtendedValue genDotProduct(mlir::Type,
261 mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
262 mlir::Value genDshiftl(mlir::Type, llvm::ArrayRef<mlir::Value>);
263 mlir::Value genDshiftr(mlir::Type, llvm::ArrayRef<mlir::Value>);
266 void genExecuteCommandLine(mlir::ArrayRef<fir::ExtendedValue> args);
267 fir::ExtendedValue genEtime(std::optional<mlir::Type>,
268 mlir::ArrayRef<fir::ExtendedValue> args);
269 mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
270 fir::ExtendedValue genExtendsTypeOf(mlir::Type,
272 template <Extremum, ExtremumBehavior>
273 mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
274 mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
275 mlir::Value genFraction(mlir::Type resultType,
276 mlir::ArrayRef<mlir::Value> args);
277 void genFree(mlir::ArrayRef<fir::ExtendedValue> args);
278 fir::ExtendedValue genFseek(std::optional<mlir::Type>,
279 mlir::ArrayRef<fir::ExtendedValue> args);
280 fir::ExtendedValue genFtell(std::optional<mlir::Type>,
281 mlir::ArrayRef<fir::ExtendedValue> args);
282 fir::ExtendedValue genGetCwd(std::optional<mlir::Type> resultType,
284 void genGetCommand(mlir::ArrayRef<fir::ExtendedValue> args);
285 mlir::Value genGetPID(mlir::Type resultType,
287 void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
288 void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
289 mlir::Value genGetGID(mlir::Type resultType,
291 mlir::Value genGetUID(mlir::Type resultType,
293 fir::ExtendedValue genHostnm(std::optional<mlir::Type> resultType,
296 mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
298 mlir::Value genIbclr(mlir::Type, llvm::ArrayRef<mlir::Value>);
299 mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
300 mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
303 mlir::Value genIeeeClass(mlir::Type, llvm::ArrayRef<mlir::Value>);
304 mlir::Value genIeeeCopySign(mlir::Type, llvm::ArrayRef<mlir::Value>);
305 void genIeeeGetFlag(llvm::ArrayRef<fir::ExtendedValue>);
306 void genIeeeGetHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
307 template <bool isGet, bool isModes>
308 void genIeeeGetOrSetModesOrStatus(llvm::ArrayRef<fir::ExtendedValue>);
309 void genIeeeGetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
310 void genIeeeGetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
311 mlir::Value genIeeeInt(mlir::Type, llvm::ArrayRef<mlir::Value>);
312 mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
313 mlir::Value genIeeeIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
314 mlir::Value genIeeeIsNegative(mlir::Type, llvm::ArrayRef<mlir::Value>);
315 mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef<mlir::Value>);
316 mlir::Value genIeeeLogb(mlir::Type, mlir::ArrayRef<mlir::Value>);
317 template <bool isMax, bool isNum, bool isMag>
318 mlir::Value genIeeeMaxMin(mlir::Type, llvm::ArrayRef<mlir::Value>);
319 template <mlir::arith::CmpFPredicate pred>
320 mlir::Value genIeeeQuietCompare(mlir::Type resultType,
322 mlir::Value genIeeeReal(mlir::Type, llvm::ArrayRef<mlir::Value>);
323 mlir::Value genIeeeRem(mlir::Type, llvm::ArrayRef<mlir::Value>);
324 mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
325 template <bool isFlag>
326 void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
327 void genIeeeSetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
328 void genIeeeSetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
329 template <mlir::arith::CmpFPredicate pred>
330 mlir::Value genIeeeSignalingCompare(mlir::Type resultType,
332 mlir::Value genIeeeSignbit(mlir::Type, llvm::ArrayRef<mlir::Value>);
333 fir::ExtendedValue genIeeeSupportFlag(mlir::Type,
335 fir::ExtendedValue genIeeeSupportHalting(mlir::Type,
337 fir::ExtendedValue genIeeeSupportRounding(mlir::Type,
339 fir::ExtendedValue genIeeeSupportStandard(mlir::Type,
341 template <mlir::arith::CmpIPredicate pred>
342 mlir::Value genIeeeTypeCompare(mlir::Type, llvm::ArrayRef<mlir::Value>);
343 mlir::Value genIeeeUnordered(mlir::Type, llvm::ArrayRef<mlir::Value>);
344 mlir::Value genIeeeValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
345 mlir::Value genIeor(mlir::Type, llvm::ArrayRef<mlir::Value>);
347 mlir::Value genIor(mlir::Type, llvm::ArrayRef<mlir::Value>);
349 fir::ExtendedValue genIsContiguous(mlir::Type,
351 template <Fortran::runtime::io::Iostat value>
352 mlir::Value genIsIostatValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
353 mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef<mlir::Value>,
354 int fpclass);
355 mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
356 mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
358 mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
362 mlir::Value genMalloc(mlir::Type, llvm::ArrayRef<mlir::Value>);
363 template <typename Shift>
364 mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
365 mlir::Value genMatchAllSync(mlir::Type, llvm::ArrayRef<mlir::Value>);
366 mlir::Value genMatchAnySync(mlir::Type, llvm::ArrayRef<mlir::Value>);
368 fir::ExtendedValue genMatmulTranspose(mlir::Type,
373 mlir::Value genMergeBits(mlir::Type, llvm::ArrayRef<mlir::Value>);
376 mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
377 mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
378 void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
380 enum class NearestProc { Nearest, NextAfter, NextDown, NextUp };
381 template <NearestProc>
382 mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
383 mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
385 mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
387 fir::ExtendedValue genNumImages(mlir::Type,
389 template <typename OpTy>
390 mlir::Value genNVVMTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
394 mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
395 mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
398 fir::ExtendedValue genPutenv(std::optional<mlir::Type>,
400 void genRandomInit(llvm::ArrayRef<fir::ExtendedValue>);
401 void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
402 void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
404 fir::ExtendedValue genReduceDim(mlir::Type,
406 fir::ExtendedValue genRename(std::optional<mlir::Type>,
407 mlir::ArrayRef<fir::ExtendedValue>);
410 mlir::Value genRRSpacing(mlir::Type resultType,
412 fir::ExtendedValue genSameTypeAs(mlir::Type,
414 mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
416 fir::ExtendedValue genSecnds(mlir::Type resultType,
418 fir::ExtendedValue genSecond(std::optional<mlir::Type>,
419 mlir::ArrayRef<fir::ExtendedValue>);
420 fir::ExtendedValue genSelectedCharKind(mlir::Type,
422 mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
423 mlir::Value genSelectedLogicalKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
424 mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
425 mlir::Value genSetExponent(mlir::Type resultType,
427 fir::ExtendedValue genShape(mlir::Type resultType,
429 template <typename Shift>
430 mlir::Value genShift(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
431 mlir::Value genShiftA(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
432 mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
433 mlir::Value genSind(mlir::Type, llvm::ArrayRef<mlir::Value>);
434 mlir::Value genSinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
437 mlir::Value genSpacing(mlir::Type resultType,
440 fir::ExtendedValue genStorageSize(mlir::Type,
443 void genSignalSubroutine(llvm::ArrayRef<fir::ExtendedValue>);
445 void genSyncThreads(llvm::ArrayRef<fir::ExtendedValue>);
446 mlir::Value genSyncThreadsAnd(mlir::Type, llvm::ArrayRef<mlir::Value>);
447 mlir::Value genSyncThreadsCount(mlir::Type, llvm::ArrayRef<mlir::Value>);
448 mlir::Value genSyncThreadsOr(mlir::Type, llvm::ArrayRef<mlir::Value>);
449 void genSyncWarp(llvm::ArrayRef<fir::ExtendedValue>);
450 fir::ExtendedValue genSystem(std::optional<mlir::Type>,
451 mlir::ArrayRef<fir::ExtendedValue> args);
452 void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
453 mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
454 mlir::Value genTanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
455 mlir::Value genTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
456 mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
457 fir::ExtendedValue genTransfer(mlir::Type,
459 fir::ExtendedValue genTranspose(mlir::Type,
461 mlir::Value genThisGrid(mlir::Type, llvm::ArrayRef<mlir::Value>);
462 fir::ExtendedValue genThisImage(mlir::Type,
464 mlir::Value genThisThreadBlock(mlir::Type, llvm::ArrayRef<mlir::Value>);
465 mlir::Value genThisWarp(mlir::Type, llvm::ArrayRef<mlir::Value>);
466 void genThreadFence(llvm::ArrayRef<fir::ExtendedValue>);
467 void genThreadFenceBlock(llvm::ArrayRef<fir::ExtendedValue>);
468 void genThreadFenceSystem(llvm::ArrayRef<fir::ExtendedValue>);
471 fir::ExtendedValue genUnlink(std::optional<mlir::Type> resultType,
475 template <mlir::NVVM::VoteSyncKind kind>
476 mlir::Value genVoteSync(mlir::Type, llvm::ArrayRef<mlir::Value>);
477
481 mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
482
488 template <typename FN, typename FD>
489 fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg,
490 mlir::Type,
492 template <typename FN, typename FD, typename FC>
494 fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar,
495 llvm::StringRef errMsg,
496 mlir::Type resultType,
499 template <typename FN, typename FD>
500 fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg,
501 mlir::Type resultType,
503
506 void genRaiseExcept(int excepts, mlir::Value cond = {});
507
509 mlir::Value genQNan(mlir::Type resultType);
510
514 using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
515 using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
517 using DualGenerator = decltype(&IntrinsicLibrary::genEtime);
518 using Generator = std::variant<ElementalGenerator, ExtendedGenerator,
519 SubroutineGenerator, DualGenerator>;
520
527 template <typename GeneratorType>
528 mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name,
529 mlir::Type resultType,
531 template <typename GeneratorType>
533 outlineInExtendedWrapper(GeneratorType, llvm::StringRef name,
534 std::optional<mlir::Type> resultType,
536
537 template <typename GeneratorType>
538 mlir::func::FuncOp getWrapper(GeneratorType, llvm::StringRef name,
539 mlir::FunctionType,
540 bool loadRefArguments = false);
541
543 template <typename GeneratorType>
545 genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType,
546 llvm::ArrayRef<fir::ExtendedValue> args, bool outline);
547
549 mlir::Value invokeGenerator(ElementalGenerator generator,
550 mlir::Type resultType,
552 mlir::Value invokeGenerator(RuntimeCallGenerator generator,
553 mlir::Type resultType,
555 mlir::Value invokeGenerator(ExtendedGenerator generator,
556 mlir::Type resultType,
558 mlir::Value invokeGenerator(SubroutineGenerator generator,
560 mlir::Value invokeGenerator(DualGenerator generator,
562 mlir::Value invokeGenerator(DualGenerator generator, mlir::Type resultType,
564
567 mlir::SymbolRefAttr
568 getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name,
569 mlir::FunctionType signature);
570
573 mlir::Type resultType,
574 llvm::StringRef errMsg);
575
576 void setResultMustBeFreed() { resultMustBeFreed = true; }
577
578 fir::FirOpBuilder &builder;
579 mlir::Location loc;
580 bool resultMustBeFreed = false;
581 Fortran::lower::AbstractConverter *converter = nullptr;
582};
583
585 const char *name = nullptr;
587 bool handleDynamicOptional = false;
588};
589
594 constexpr bool hasDefaultRules() const { return args[0].name == nullptr; }
595};
596
600 const char *name;
601 IntrinsicLibrary::Generator generator;
602 // The following may be omitted in the table below.
603 fir::IntrinsicArgumentLoweringRules argLoweringRules = {};
604 bool isElemental = true;
607 bool outline = false;
608};
609
611 // llvm::StringRef comparison operator are not constexpr, so use string_view.
612 using Key = std::string_view;
613 // Needed for implicit compare with keys.
614 constexpr operator Key() const { return key; }
615 Key key; // intrinsic name
616
617 // Name of a runtime function that implements the operation.
618 llvm::StringRef symbol;
619 fir::runtime::FuncTypeBuilderFunc typeGenerator;
620};
621
623 // Callback type for generating lowering for a math operation.
624 using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location,
625 const MathOperation &,
626 mlir::FunctionType,
628
629 // Overrides fir::runtime::FuncTypeBuilderFunc to add FirOpBuilder argument.
630 using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *,
632
633 // llvm::StringRef comparison operator are not constexpr, so use string_view.
634 using Key = std::string_view;
635 // Needed for implicit compare with keys.
636 constexpr operator Key() const { return key; }
637 // Intrinsic name.
638 Key key;
639
640 // Name of a runtime function that implements the operation.
641 llvm::StringRef runtimeFunc;
642 FuncTypeBuilderFunc typeGenerator;
643
644 // A callback to generate FIR for the intrinsic defined by 'key'.
645 // A callback may generate either dedicated MLIR operation(s) or
646 // a function call to a runtime function with name defined by
647 // 'runtimeFunc'.
648 MathGeneratorTy funcGenerator;
649};
650
651// Enum of most supported intrinsic argument or return types.
652enum class ParamTypeId {
653 Void,
654 Address, // pointer (to an [array of] Integers of some kind)
655 Integer,
656 Real,
657 Complex,
658 IntegerVector,
659 UnsignedVector,
660 RealVector,
661};
662
663// Helper function to get length of a 16-byte vector of element type eleTy.
664static int getVecLen(mlir::Type eleTy) {
665 assert((mlir::isa<mlir::IntegerType>(eleTy) ||
666 mlir::isa<mlir::FloatType>(eleTy)) &&
667 "unsupported vector element type");
668 return 16 / (eleTy.getIntOrFloatBitWidth() / 8);
669}
670
671template <ParamTypeId t, int k>
672struct ParamType {
673 // Supported kinds can be checked with static asserts at compile time.
674 static_assert(t != ParamTypeId::Integer || k == 1 || k == 2 || k == 4 ||
675 k == 8,
676 "Unsupported integer kind");
677 static_assert(t != ParamTypeId::Real || k == 4 || k == 8 || k == 10 ||
678 k == 16,
679 "Unsupported real kind");
680 static_assert(t != ParamTypeId::Complex || k == 2 || k == 3 || k == 4 ||
681 k == 8 || k == 10 || k == 16,
682 "Unsupported complex kind");
683
684 static const ParamTypeId ty = t;
685 static const int kind = k;
686};
687
688// Namespace encapsulating type definitions for parameter types.
689namespace Ty {
691template <int k>
693template <int k>
695template <int k>
697template <int k>
699template <int k>
700using IntegerVector = ParamType<ParamTypeId::IntegerVector, k>;
701template <int k>
702using UnsignedVector = ParamType<ParamTypeId::UnsignedVector, k>;
703template <int k>
705} // namespace Ty
706
707// Helper function that generates most types that are supported for intrinsic
708// arguments and return type. Used by `genFuncType` to generate function
709// types for most of the intrinsics.
710static inline mlir::Type getTypeHelper(mlir::MLIRContext *context,
711 fir::FirOpBuilder &builder,
712 ParamTypeId typeId, int kind) {
713 mlir::Type r;
714 unsigned bits{0};
715 switch (typeId) {
716 case ParamTypeId::Void:
717 llvm::report_fatal_error("can not get type of void");
718 break;
719 case ParamTypeId::Address:
720 bits = builder.getKindMap().getIntegerBitsize(kind);
721 assert(bits != 0 && "failed to convert address kind to integer bitsize");
722 r = fir::ReferenceType::get(mlir::IntegerType::get(context, bits));
723 break;
724 case ParamTypeId::Integer:
725 case ParamTypeId::IntegerVector:
726 bits = builder.getKindMap().getIntegerBitsize(kind);
727 assert(bits != 0 && "failed to convert kind to integer bitsize");
728 r = mlir::IntegerType::get(context, bits);
729 break;
730 case ParamTypeId::UnsignedVector:
731 bits = builder.getKindMap().getIntegerBitsize(kind);
732 assert(bits != 0 && "failed to convert kind to unsigned bitsize");
733 r = mlir::IntegerType::get(context, bits, mlir::IntegerType::Unsigned);
734 break;
735 case ParamTypeId::Real:
736 case ParamTypeId::RealVector:
737 r = builder.getRealType(kind);
738 break;
739 case ParamTypeId::Complex:
740 r = mlir::ComplexType::get(builder.getRealType(kind));
741 break;
742 }
743
744 switch (typeId) {
745 case ParamTypeId::Void:
746 case ParamTypeId::Address:
747 case ParamTypeId::Integer:
748 case ParamTypeId::Real:
749 case ParamTypeId::Complex:
750 break;
751 case ParamTypeId::IntegerVector:
752 case ParamTypeId::UnsignedVector:
753 case ParamTypeId::RealVector:
754 // convert to vector type
755 r = fir::VectorType::get(getVecLen(r), r);
756 }
757 return r;
758}
759
760// Generic function type generator that supports most of the function types
761// used by intrinsics.
762template <typename TyR, typename... ArgTys>
763static inline mlir::FunctionType genFuncType(mlir::MLIRContext *context,
764 fir::FirOpBuilder &builder) {
765 llvm::SmallVector<ParamTypeId> argTys = {ArgTys::ty...};
766 llvm::SmallVector<int> argKinds = {ArgTys::kind...};
767 llvm::SmallVector<mlir::Type> argTypes;
768
769 for (size_t i = 0; i < argTys.size(); ++i) {
770 argTypes.push_back(getTypeHelper(context, builder, argTys[i], argKinds[i]));
771 }
772
773 if (TyR::ty == ParamTypeId::Void)
774 return mlir::FunctionType::get(context, argTypes, {});
775
776 auto resType = getTypeHelper(context, builder, TyR::ty, TyR::kind);
777 return mlir::FunctionType::get(context, argTypes, {resType});
778}
779
781struct IntrinsicHandlerEntry {
782 using RuntimeGeneratorRange =
783 std::pair<const MathOperation *, const MathOperation *>;
784 IntrinsicHandlerEntry(const IntrinsicHandler *handler) : entry{handler} {
785 assert(handler && "handler must not be nullptr");
786 };
787 IntrinsicHandlerEntry(RuntimeGeneratorRange rt) : entry{rt} {};
788 const IntrinsicArgumentLoweringRules *getArgumentLoweringRules() const;
789 std::variant<const IntrinsicHandler *, RuntimeGeneratorRange> entry;
790};
791
792//===----------------------------------------------------------------------===//
793// Helper functions for argument handling.
794//===----------------------------------------------------------------------===//
795static inline mlir::Type getConvertedElementType(mlir::MLIRContext *context,
796 mlir::Type eleTy) {
797 if (mlir::isa<mlir::IntegerType>(eleTy) && !eleTy.isSignlessInteger()) {
798 const auto intTy{mlir::dyn_cast<mlir::IntegerType>(eleTy)};
799 auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
800 return newEleTy;
801 }
802 return eleTy;
803}
804
805static inline llvm::SmallVector<mlir::Value, 4>
806getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
807 llvm::SmallVector<mlir::Value, 4> baseVec;
808 for (auto arg : args)
809 baseVec.push_back(getBase(arg));
810 return baseVec;
811}
812
813static inline llvm::SmallVector<mlir::Type, 4>
814getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
815 llvm::SmallVector<mlir::Type, 4> typeVec;
816 for (auto arg : args)
817 typeVec.push_back(arg.getType());
818 return typeVec;
819}
820
821mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
822 const MathOperation &mathOp,
823 mlir::FunctionType libFuncType,
824 llvm::ArrayRef<mlir::Value> args);
825
826template <typename T>
827mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
828 const MathOperation &mathOp,
829 mlir::FunctionType mathLibFuncType,
830 llvm::ArrayRef<mlir::Value> args);
831
832template <typename T>
833mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
834 const MathOperation &mathOp,
835 mlir::FunctionType mathLibFuncType,
836 llvm::ArrayRef<mlir::Value> args);
837
838mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
839 mlir::Location loc,
840 const MathOperation &mathOp,
841 mlir::FunctionType libFuncType,
842 llvm::ArrayRef<mlir::Value> args);
843
846std::optional<IntrinsicHandlerEntry>
847lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName,
848 std::optional<mlir::Type> resultType);
849
851void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name);
852
856getIntrinsicArgumentLowering(llvm::StringRef intrinsicName);
857
861 unsigned position);
862
864fir::ExtendedValue getAbsentIntrinsicArgument();
865
867// implementation) of an unrestricted intrinsic (defined by its signature
868// and generic name)
869mlir::SymbolRefAttr
870getUnrestrictedIntrinsicSymbolRefAttr(fir::FirOpBuilder &, mlir::Location,
871 llvm::StringRef name,
872 mlir::FunctionType signature);
873
874//===----------------------------------------------------------------------===//
875// Direct access to intrinsics that may be used by lowering outside
876// of intrinsic call lowering.
877//===----------------------------------------------------------------------===//
878
881mlir::Value genMax(fir::FirOpBuilder &, mlir::Location,
882 llvm::ArrayRef<mlir::Value> args);
883
885mlir::Value genMin(fir::FirOpBuilder &, mlir::Location,
886 llvm::ArrayRef<mlir::Value> args);
887
890mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
891 mlir::Type resultType, mlir::Value x, mlir::Value y);
892
895mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType,
896 mlir::Value x, mlir::Value y);
897
898} // namespace fir
899
900#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:89
Definition AbstractConverter.h:34
std::optional< IntrinsicHandlerEntry > lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName, std::optional< mlir::Type > resultType)
Definition IntrinsicCall.cpp:2101
Extremum
Enums used to templatize and share lowering of MIN and MAX.
Definition IntrinsicCall.h:53
const IntrinsicArgumentLoweringRules * getIntrinsicArgumentLowering(llvm::StringRef intrinsicName)
Definition IntrinsicCall.cpp:9504
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:9558
mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:9571
mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:9566
fir::ExtendedValue getAbsentIntrinsicArgument()
Return place-holder for absent intrinsic arguments.
Definition IntrinsicCall.cpp:78
void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name)
Generate a TODO error message for an as yet unimplemented intrinsic.
Definition IntrinsicCall.cpp:2123
ArgLoweringRule lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &, unsigned position)
Definition IntrinsicCall.cpp:9529
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:9592
LowerIntrinsicArgAs
Definition IntrinsicCall.h:97
@ Addr
Definition IntrinsicCall.h:102
@ Inquired
Definition IntrinsicCall.h:108
@ Box
Lower argument to a box.
Definition IntrinsicCall.h:104
@ Value
Lower argument to a value. Mainly intended for scalar arguments.
Definition IntrinsicCall.h:99
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:9542
mlir::Value genMax(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:9550
Define how a given intrinsic argument must be lowered.
Definition IntrinsicCall.h:112
bool handleDynamicOptional
Value:
Definition IntrinsicCall.h:124
This is shared by intrinsics and intrinsic module procedures.
Definition IntrinsicCall.h:591
IntrinsicDummyArgument args[7]
There is no more than 7 non repeated arguments in Fortran intrinsics.
Definition IntrinsicCall.h:593
Definition IntrinsicCall.h:584
Entry into the tables describing how an intrinsic must be lowered.
Definition IntrinsicCall.h:781
Definition IntrinsicCall.h:599
bool outline
Definition IntrinsicCall.h:607
mlir::SymbolRefAttr getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name, mlir::FunctionType signature)
Definition IntrinsicCall.cpp:2629
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:2135
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:4739
std::pair< fir::ExtendedValue, bool > genIntrinsicCall(llvm::StringRef name, std::optional< mlir::Type > resultType, llvm::ArrayRef< fir::ExtendedValue > arg)
Definition IntrinsicCall.cpp:2319
decltype(&IntrinsicLibrary::genEtime) DualGenerator
The generator for intrinsic that has both function and subroutine form.
Definition IntrinsicCall.h:517
mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name, mlir::Type resultType, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:2528
mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2700
mlir::Value genQNan(mlir::Type resultType)
Generate a quiet NaN of a given floating point type.
Definition IntrinsicCall.cpp:4952
mlir::Value genConversion(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2708
mlir::Value genAbs(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2722
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:9413
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:2663
decltype(&IntrinsicLibrary::genAbs) ElementalGenerator
Definition IntrinsicCall.h:513
fir::ExtendedValue genCAssociatedCPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_PTR [, C_PTR])
Definition IntrinsicCall.cpp:3509
fir::ExtendedValue genCAssociatedCFunPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_FUNPTR [, C_FUNPTR])
Definition IntrinsicCall.cpp:3502
void genRaiseExcept(int excepts, mlir::Value cond={})
Definition IntrinsicCall.cpp:4959
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:2334
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:9332
Definition IntrinsicCall.h:622
Definition IntrinsicCall.h:672
Definition IntrinsicCall.h:610