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 mlir::Value genBarrierArrive(mlir::Type, llvm::ArrayRef<mlir::Value>);
212 mlir::Value genBarrierArriveCnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
213 void genBarrierInit(llvm::ArrayRef<fir::ExtendedValue>);
214 fir::ExtendedValue genBesselJn(mlir::Type,
216 fir::ExtendedValue genBesselYn(mlir::Type,
218 template <mlir::arith::CmpIPredicate pred>
219 mlir::Value genBitwiseCompare(mlir::Type resultType,
221
222 mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
223 mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
225 fir::ExtendedValue genChdir(std::optional<mlir::Type> resultType,
227 template <mlir::arith::CmpIPredicate pred>
228 fir::ExtendedValue genCharacterCompare(mlir::Type,
230 mlir::Value genCmplx(mlir::Type, llvm::ArrayRef<mlir::Value>);
231 mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
233 void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
235 template <const char *fctName, int extent>
236 fir::ExtendedValue genCUDALDXXFunc(mlir::Type,
243 mlir::Value genErfcScaled(mlir::Type resultType,
245 void genCFPointer(llvm::ArrayRef<fir::ExtendedValue>);
246 void genCFProcPointer(llvm::ArrayRef<fir::ExtendedValue>);
249 template <mlir::arith::CmpIPredicate pred>
250 fir::ExtendedValue genCPtrCompare(mlir::Type,
252 void genCoBroadcast(llvm::ArrayRef<fir::ExtendedValue>);
256 mlir::Value genCosd(mlir::Type, llvm::ArrayRef<mlir::Value>);
257 mlir::Value genCospi(mlir::Type, llvm::ArrayRef<mlir::Value>);
258 void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
259 fir::ExtendedValue genDsecnds(mlir::Type resultType,
261 mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
262 fir::ExtendedValue genDotProduct(mlir::Type,
264 mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
265 mlir::Value genDshiftl(mlir::Type, llvm::ArrayRef<mlir::Value>);
266 mlir::Value genDshiftr(mlir::Type, llvm::ArrayRef<mlir::Value>);
269 void genExecuteCommandLine(mlir::ArrayRef<fir::ExtendedValue> args);
270 fir::ExtendedValue genEtime(std::optional<mlir::Type>,
271 mlir::ArrayRef<fir::ExtendedValue> args);
272 mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
273 fir::ExtendedValue genExtendsTypeOf(mlir::Type,
275 template <Extremum, ExtremumBehavior>
276 mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
277 void genFenceProxyAsync(llvm::ArrayRef<fir::ExtendedValue>);
278 mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
279 mlir::Value genFraction(mlir::Type resultType,
280 mlir::ArrayRef<mlir::Value> args);
281 void genFree(mlir::ArrayRef<fir::ExtendedValue> args);
282 fir::ExtendedValue genFseek(std::optional<mlir::Type>,
283 mlir::ArrayRef<fir::ExtendedValue> args);
284 fir::ExtendedValue genFtell(std::optional<mlir::Type>,
285 mlir::ArrayRef<fir::ExtendedValue> args);
286 fir::ExtendedValue genGetCwd(std::optional<mlir::Type> resultType,
288 void genGetCommand(mlir::ArrayRef<fir::ExtendedValue> args);
289 mlir::Value genGetPID(mlir::Type resultType,
291 void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
292 void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
293 mlir::Value genGetGID(mlir::Type resultType,
295 mlir::Value genGetUID(mlir::Type resultType,
297 fir::ExtendedValue genHostnm(std::optional<mlir::Type> resultType,
300 mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
302 mlir::Value genIbclr(mlir::Type, llvm::ArrayRef<mlir::Value>);
303 mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
304 mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
307 mlir::Value genIeeeClass(mlir::Type, llvm::ArrayRef<mlir::Value>);
308 mlir::Value genIeeeCopySign(mlir::Type, llvm::ArrayRef<mlir::Value>);
309 void genIeeeGetFlag(llvm::ArrayRef<fir::ExtendedValue>);
310 void genIeeeGetHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
311 template <bool isGet, bool isModes>
312 void genIeeeGetOrSetModesOrStatus(llvm::ArrayRef<fir::ExtendedValue>);
313 void genIeeeGetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
314 void genIeeeGetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
315 mlir::Value genIeeeInt(mlir::Type, llvm::ArrayRef<mlir::Value>);
316 mlir::Value genIeeeIsFinite(mlir::Type, llvm::ArrayRef<mlir::Value>);
317 mlir::Value genIeeeIsNan(mlir::Type, llvm::ArrayRef<mlir::Value>);
318 mlir::Value genIeeeIsNegative(mlir::Type, llvm::ArrayRef<mlir::Value>);
319 mlir::Value genIeeeIsNormal(mlir::Type, llvm::ArrayRef<mlir::Value>);
320 mlir::Value genIeeeLogb(mlir::Type, mlir::ArrayRef<mlir::Value>);
321 template <bool isMax, bool isNum, bool isMag>
322 mlir::Value genIeeeMaxMin(mlir::Type, llvm::ArrayRef<mlir::Value>);
323 template <mlir::arith::CmpFPredicate pred>
324 mlir::Value genIeeeQuietCompare(mlir::Type resultType,
326 mlir::Value genIeeeReal(mlir::Type, llvm::ArrayRef<mlir::Value>);
327 mlir::Value genIeeeRem(mlir::Type, llvm::ArrayRef<mlir::Value>);
328 mlir::Value genIeeeRint(mlir::Type, llvm::ArrayRef<mlir::Value>);
329 template <bool isFlag>
330 void genIeeeSetFlagOrHaltingMode(llvm::ArrayRef<fir::ExtendedValue>);
331 void genIeeeSetRoundingMode(llvm::ArrayRef<fir::ExtendedValue>);
332 void genIeeeSetUnderflowMode(llvm::ArrayRef<fir::ExtendedValue>);
333 template <mlir::arith::CmpFPredicate pred>
334 mlir::Value genIeeeSignalingCompare(mlir::Type resultType,
336 mlir::Value genIeeeSignbit(mlir::Type, llvm::ArrayRef<mlir::Value>);
337 fir::ExtendedValue genIeeeSupportFlag(mlir::Type,
339 fir::ExtendedValue genIeeeSupportHalting(mlir::Type,
341 fir::ExtendedValue genIeeeSupportRounding(mlir::Type,
343 fir::ExtendedValue genIeeeSupportStandard(mlir::Type,
345 template <mlir::arith::CmpIPredicate pred>
346 mlir::Value genIeeeTypeCompare(mlir::Type, llvm::ArrayRef<mlir::Value>);
347 mlir::Value genIeeeUnordered(mlir::Type, llvm::ArrayRef<mlir::Value>);
348 mlir::Value genIeeeValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
349 mlir::Value genIeor(mlir::Type, llvm::ArrayRef<mlir::Value>);
351 mlir::Value genIor(mlir::Type, llvm::ArrayRef<mlir::Value>);
353 fir::ExtendedValue genIsContiguous(mlir::Type,
355 template <Fortran::runtime::io::Iostat value>
356 mlir::Value genIsIostatValue(mlir::Type, llvm::ArrayRef<mlir::Value>);
357 mlir::Value genIsFPClass(mlir::Type, llvm::ArrayRef<mlir::Value>,
358 int fpclass);
359 mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
360 mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
362 mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
366 mlir::Value genMalloc(mlir::Type, llvm::ArrayRef<mlir::Value>);
367 template <typename Shift>
368 mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
369 mlir::Value genMatchAllSync(mlir::Type, llvm::ArrayRef<mlir::Value>);
370 mlir::Value genMatchAnySync(mlir::Type, llvm::ArrayRef<mlir::Value>);
372 fir::ExtendedValue genMatmulTranspose(mlir::Type,
377 mlir::Value genMergeBits(mlir::Type, llvm::ArrayRef<mlir::Value>);
380 mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
381 mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
382 void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
384 enum class NearestProc { Nearest, NextAfter, NextDown, NextUp };
385 template <NearestProc>
386 mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
387 mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
389 mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
391 fir::ExtendedValue genNumImages(mlir::Type,
393 template <typename OpTy>
394 mlir::Value genNVVMTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
398 mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
399 mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
402 fir::ExtendedValue genPutenv(std::optional<mlir::Type>,
404 void genRandomInit(llvm::ArrayRef<fir::ExtendedValue>);
405 void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
406 void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
408 fir::ExtendedValue genReduceDim(mlir::Type,
410 fir::ExtendedValue genRename(std::optional<mlir::Type>,
411 mlir::ArrayRef<fir::ExtendedValue>);
414 mlir::Value genRRSpacing(mlir::Type resultType,
416 fir::ExtendedValue genSameTypeAs(mlir::Type,
418 mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
420 fir::ExtendedValue genSecnds(mlir::Type resultType,
422 fir::ExtendedValue genSecond(std::optional<mlir::Type>,
423 mlir::ArrayRef<fir::ExtendedValue>);
424 fir::ExtendedValue genSelectedCharKind(mlir::Type,
426 mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
427 mlir::Value genSelectedLogicalKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
428 mlir::Value genSelectedRealKind(mlir::Type, llvm::ArrayRef<mlir::Value>);
429 mlir::Value genSetExponent(mlir::Type resultType,
431 fir::ExtendedValue genShape(mlir::Type resultType,
433 template <typename Shift>
434 mlir::Value genShift(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
435 mlir::Value genShiftA(mlir::Type resultType, llvm::ArrayRef<mlir::Value>);
436 mlir::Value genSign(mlir::Type, llvm::ArrayRef<mlir::Value>);
437 mlir::Value genSind(mlir::Type, llvm::ArrayRef<mlir::Value>);
438 mlir::Value genSinpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
441 mlir::Value genSpacing(mlir::Type resultType,
444 fir::ExtendedValue genStorageSize(mlir::Type,
447 void genSignalSubroutine(llvm::ArrayRef<fir::ExtendedValue>);
449 void genSyncThreads(llvm::ArrayRef<fir::ExtendedValue>);
450 mlir::Value genSyncThreadsAnd(mlir::Type, llvm::ArrayRef<mlir::Value>);
451 mlir::Value genSyncThreadsCount(mlir::Type, llvm::ArrayRef<mlir::Value>);
452 mlir::Value genSyncThreadsOr(mlir::Type, llvm::ArrayRef<mlir::Value>);
453 void genSyncWarp(llvm::ArrayRef<fir::ExtendedValue>);
454 fir::ExtendedValue genSystem(std::optional<mlir::Type>,
455 mlir::ArrayRef<fir::ExtendedValue> args);
456 void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
457 mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
458 mlir::Value genTanpi(mlir::Type, llvm::ArrayRef<mlir::Value>);
459 mlir::Value genTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
460 void genTMABulkCommitGroup(llvm::ArrayRef<fir::ExtendedValue>);
461 void genTMABulkG2S(llvm::ArrayRef<fir::ExtendedValue>);
462 void genTMABulkS2G(llvm::ArrayRef<fir::ExtendedValue>);
463 void genTMABulkWaitGroup(llvm::ArrayRef<fir::ExtendedValue>);
464 mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
465 fir::ExtendedValue genTransfer(mlir::Type,
467 fir::ExtendedValue genTranspose(mlir::Type,
469 mlir::Value genThisGrid(mlir::Type, llvm::ArrayRef<mlir::Value>);
470 fir::ExtendedValue genThisImage(mlir::Type,
472 mlir::Value genThisThreadBlock(mlir::Type, llvm::ArrayRef<mlir::Value>);
473 mlir::Value genThisWarp(mlir::Type, llvm::ArrayRef<mlir::Value>);
474 void genThreadFence(llvm::ArrayRef<fir::ExtendedValue>);
475 void genThreadFenceBlock(llvm::ArrayRef<fir::ExtendedValue>);
476 void genThreadFenceSystem(llvm::ArrayRef<fir::ExtendedValue>);
479 fir::ExtendedValue genUnlink(std::optional<mlir::Type> resultType,
483 template <mlir::NVVM::VoteSyncKind kind>
484 mlir::Value genVoteSync(mlir::Type, llvm::ArrayRef<mlir::Value>);
485
489 mlir::Value genConversion(mlir::Type, llvm::ArrayRef<mlir::Value>);
490
496 template <typename FN, typename FD>
497 fir::ExtendedValue genExtremumloc(FN func, FD funcDim, llvm::StringRef errMsg,
498 mlir::Type,
500 template <typename FN, typename FD, typename FC>
502 fir::ExtendedValue genExtremumVal(FN func, FD funcDim, FC funcChar,
503 llvm::StringRef errMsg,
504 mlir::Type resultType,
507 template <typename FN, typename FD>
508 fir::ExtendedValue genReduction(FN func, FD funcDim, llvm::StringRef errMsg,
509 mlir::Type resultType,
511
514 void genRaiseExcept(int excepts, mlir::Value cond = {});
515
517 mlir::Value genQNan(mlir::Type resultType);
518
522 using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
523 using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
525 using DualGenerator = decltype(&IntrinsicLibrary::genEtime);
526 using Generator = std::variant<ElementalGenerator, ExtendedGenerator,
527 SubroutineGenerator, DualGenerator>;
528
535 template <typename GeneratorType>
536 mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name,
537 mlir::Type resultType,
539 template <typename GeneratorType>
541 outlineInExtendedWrapper(GeneratorType, llvm::StringRef name,
542 std::optional<mlir::Type> resultType,
544
545 template <typename GeneratorType>
546 mlir::func::FuncOp getWrapper(GeneratorType, llvm::StringRef name,
547 mlir::FunctionType,
548 bool loadRefArguments = false);
549
551 template <typename GeneratorType>
553 genElementalCall(GeneratorType, llvm::StringRef name, mlir::Type resultType,
554 llvm::ArrayRef<fir::ExtendedValue> args, bool outline);
555
557 mlir::Value invokeGenerator(ElementalGenerator generator,
558 mlir::Type resultType,
560 mlir::Value invokeGenerator(RuntimeCallGenerator generator,
561 mlir::Type resultType,
563 mlir::Value invokeGenerator(ExtendedGenerator generator,
564 mlir::Type resultType,
566 mlir::Value invokeGenerator(SubroutineGenerator generator,
568 mlir::Value invokeGenerator(DualGenerator generator,
570 mlir::Value invokeGenerator(DualGenerator generator, mlir::Type resultType,
572
575 mlir::SymbolRefAttr
576 getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name,
577 mlir::FunctionType signature);
578
581 mlir::Type resultType,
582 llvm::StringRef errMsg);
583
584 void setResultMustBeFreed() { resultMustBeFreed = true; }
585
586 fir::FirOpBuilder &builder;
587 mlir::Location loc;
588 bool resultMustBeFreed = false;
589 Fortran::lower::AbstractConverter *converter = nullptr;
590};
591
593 const char *name = nullptr;
595 bool handleDynamicOptional = false;
596};
597
602 constexpr bool hasDefaultRules() const { return args[0].name == nullptr; }
603};
604
608 const char *name;
609 IntrinsicLibrary::Generator generator;
610 // The following may be omitted in the table below.
611 fir::IntrinsicArgumentLoweringRules argLoweringRules = {};
612 bool isElemental = true;
615 bool outline = false;
616};
617
619 // llvm::StringRef comparison operator are not constexpr, so use string_view.
620 using Key = std::string_view;
621 // Needed for implicit compare with keys.
622 constexpr operator Key() const { return key; }
623 Key key; // intrinsic name
624
625 // Name of a runtime function that implements the operation.
626 llvm::StringRef symbol;
627 fir::runtime::FuncTypeBuilderFunc typeGenerator;
628};
629
631 // Callback type for generating lowering for a math operation.
632 using MathGeneratorTy = mlir::Value (*)(fir::FirOpBuilder &, mlir::Location,
633 const MathOperation &,
634 mlir::FunctionType,
636
637 // Overrides fir::runtime::FuncTypeBuilderFunc to add FirOpBuilder argument.
638 using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *,
640
641 // llvm::StringRef comparison operator are not constexpr, so use string_view.
642 using Key = std::string_view;
643 // Needed for implicit compare with keys.
644 constexpr operator Key() const { return key; }
645 // Intrinsic name.
646 Key key;
647
648 // Name of a runtime function that implements the operation.
649 llvm::StringRef runtimeFunc;
650 FuncTypeBuilderFunc typeGenerator;
651
652 // A callback to generate FIR for the intrinsic defined by 'key'.
653 // A callback may generate either dedicated MLIR operation(s) or
654 // a function call to a runtime function with name defined by
655 // 'runtimeFunc'.
656 MathGeneratorTy funcGenerator;
657};
658
659// Enum of most supported intrinsic argument or return types.
660enum class ParamTypeId {
661 Void,
662 Address, // pointer (to an [array of] Integers of some kind)
663 Integer,
664 Real,
665 Complex,
666 IntegerVector,
667 UnsignedVector,
668 RealVector,
669};
670
671// Helper function to get length of a 16-byte vector of element type eleTy.
672static int getVecLen(mlir::Type eleTy) {
673 assert((mlir::isa<mlir::IntegerType>(eleTy) ||
674 mlir::isa<mlir::FloatType>(eleTy)) &&
675 "unsupported vector element type");
676 return 16 / (eleTy.getIntOrFloatBitWidth() / 8);
677}
678
679template <ParamTypeId t, int k>
680struct ParamType {
681 // Supported kinds can be checked with static asserts at compile time.
682 static_assert(t != ParamTypeId::Integer || k == 1 || k == 2 || k == 4 ||
683 k == 8,
684 "Unsupported integer kind");
685 static_assert(t != ParamTypeId::Real || k == 4 || k == 8 || k == 10 ||
686 k == 16,
687 "Unsupported real kind");
688 static_assert(t != ParamTypeId::Complex || k == 2 || k == 3 || k == 4 ||
689 k == 8 || k == 10 || k == 16,
690 "Unsupported complex kind");
691
692 static const ParamTypeId ty = t;
693 static const int kind = k;
694};
695
696// Namespace encapsulating type definitions for parameter types.
697namespace Ty {
699template <int k>
701template <int k>
703template <int k>
705template <int k>
707template <int k>
708using IntegerVector = ParamType<ParamTypeId::IntegerVector, k>;
709template <int k>
710using UnsignedVector = ParamType<ParamTypeId::UnsignedVector, k>;
711template <int k>
713} // namespace Ty
714
715// Helper function that generates most types that are supported for intrinsic
716// arguments and return type. Used by `genFuncType` to generate function
717// types for most of the intrinsics.
718static inline mlir::Type getTypeHelper(mlir::MLIRContext *context,
719 fir::FirOpBuilder &builder,
720 ParamTypeId typeId, int kind) {
721 mlir::Type r;
722 unsigned bits{0};
723 switch (typeId) {
724 case ParamTypeId::Void:
725 llvm::report_fatal_error("can not get type of void");
726 break;
727 case ParamTypeId::Address:
728 bits = builder.getKindMap().getIntegerBitsize(kind);
729 assert(bits != 0 && "failed to convert address kind to integer bitsize");
730 r = fir::ReferenceType::get(mlir::IntegerType::get(context, bits));
731 break;
732 case ParamTypeId::Integer:
733 case ParamTypeId::IntegerVector:
734 bits = builder.getKindMap().getIntegerBitsize(kind);
735 assert(bits != 0 && "failed to convert kind to integer bitsize");
736 r = mlir::IntegerType::get(context, bits);
737 break;
738 case ParamTypeId::UnsignedVector:
739 bits = builder.getKindMap().getIntegerBitsize(kind);
740 assert(bits != 0 && "failed to convert kind to unsigned bitsize");
741 r = mlir::IntegerType::get(context, bits, mlir::IntegerType::Unsigned);
742 break;
743 case ParamTypeId::Real:
744 case ParamTypeId::RealVector:
745 r = builder.getRealType(kind);
746 break;
747 case ParamTypeId::Complex:
748 r = mlir::ComplexType::get(builder.getRealType(kind));
749 break;
750 }
751
752 switch (typeId) {
753 case ParamTypeId::Void:
754 case ParamTypeId::Address:
755 case ParamTypeId::Integer:
756 case ParamTypeId::Real:
757 case ParamTypeId::Complex:
758 break;
759 case ParamTypeId::IntegerVector:
760 case ParamTypeId::UnsignedVector:
761 case ParamTypeId::RealVector:
762 // convert to vector type
763 r = fir::VectorType::get(getVecLen(r), r);
764 }
765 return r;
766}
767
768// Generic function type generator that supports most of the function types
769// used by intrinsics.
770template <typename TyR, typename... ArgTys>
771static inline mlir::FunctionType genFuncType(mlir::MLIRContext *context,
772 fir::FirOpBuilder &builder) {
773 llvm::SmallVector<ParamTypeId> argTys = {ArgTys::ty...};
774 llvm::SmallVector<int> argKinds = {ArgTys::kind...};
775 llvm::SmallVector<mlir::Type> argTypes;
776
777 for (size_t i = 0; i < argTys.size(); ++i) {
778 argTypes.push_back(getTypeHelper(context, builder, argTys[i], argKinds[i]));
779 }
780
781 if (TyR::ty == ParamTypeId::Void)
782 return mlir::FunctionType::get(context, argTypes, {});
783
784 auto resType = getTypeHelper(context, builder, TyR::ty, TyR::kind);
785 return mlir::FunctionType::get(context, argTypes, {resType});
786}
787
789struct IntrinsicHandlerEntry {
790 using RuntimeGeneratorRange =
791 std::pair<const MathOperation *, const MathOperation *>;
792 IntrinsicHandlerEntry(const IntrinsicHandler *handler) : entry{handler} {
793 assert(handler && "handler must not be nullptr");
794 };
795 IntrinsicHandlerEntry(RuntimeGeneratorRange rt) : entry{rt} {};
796 const IntrinsicArgumentLoweringRules *getArgumentLoweringRules() const;
797 std::variant<const IntrinsicHandler *, RuntimeGeneratorRange> entry;
798};
799
800//===----------------------------------------------------------------------===//
801// Helper functions for argument handling.
802//===----------------------------------------------------------------------===//
803static inline mlir::Type getConvertedElementType(mlir::MLIRContext *context,
804 mlir::Type eleTy) {
805 if (mlir::isa<mlir::IntegerType>(eleTy) && !eleTy.isSignlessInteger()) {
806 const auto intTy{mlir::dyn_cast<mlir::IntegerType>(eleTy)};
807 auto newEleTy{mlir::IntegerType::get(context, intTy.getWidth())};
808 return newEleTy;
809 }
810 return eleTy;
811}
812
813static inline llvm::SmallVector<mlir::Value, 4>
814getBasesForArgs(llvm::ArrayRef<fir::ExtendedValue> args) {
815 llvm::SmallVector<mlir::Value, 4> baseVec;
816 for (auto arg : args)
817 baseVec.push_back(getBase(arg));
818 return baseVec;
819}
820
821static inline llvm::SmallVector<mlir::Type, 4>
822getTypesForArgs(llvm::ArrayRef<mlir::Value> args) {
823 llvm::SmallVector<mlir::Type, 4> typeVec;
824 for (auto arg : args)
825 typeVec.push_back(arg.getType());
826 return typeVec;
827}
828
829mlir::Value genLibCall(fir::FirOpBuilder &builder, mlir::Location loc,
830 const MathOperation &mathOp,
831 mlir::FunctionType libFuncType,
832 llvm::ArrayRef<mlir::Value> args);
833
834template <typename T>
835mlir::Value genMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
836 const MathOperation &mathOp,
837 mlir::FunctionType mathLibFuncType,
838 llvm::ArrayRef<mlir::Value> args);
839
840template <typename T>
841mlir::Value genComplexMathOp(fir::FirOpBuilder &builder, mlir::Location loc,
842 const MathOperation &mathOp,
843 mlir::FunctionType mathLibFuncType,
844 llvm::ArrayRef<mlir::Value> args);
845
846mlir::Value genLibSplitComplexArgsCall(fir::FirOpBuilder &builder,
847 mlir::Location loc,
848 const MathOperation &mathOp,
849 mlir::FunctionType libFuncType,
850 llvm::ArrayRef<mlir::Value> args);
851
854std::optional<IntrinsicHandlerEntry>
855lookupIntrinsicHandler(fir::FirOpBuilder &, llvm::StringRef intrinsicName,
856 std::optional<mlir::Type> resultType);
857
859void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name);
860
864getIntrinsicArgumentLowering(llvm::StringRef intrinsicName);
865
869 unsigned position);
870
872fir::ExtendedValue getAbsentIntrinsicArgument();
873
875// implementation) of an unrestricted intrinsic (defined by its signature
876// and generic name)
877mlir::SymbolRefAttr
878getUnrestrictedIntrinsicSymbolRefAttr(fir::FirOpBuilder &, mlir::Location,
879 llvm::StringRef name,
880 mlir::FunctionType signature);
881
882//===----------------------------------------------------------------------===//
883// Direct access to intrinsics that may be used by lowering outside
884// of intrinsic call lowering.
885//===----------------------------------------------------------------------===//
886
889mlir::Value genMax(fir::FirOpBuilder &, mlir::Location,
890 llvm::ArrayRef<mlir::Value> args);
891
893mlir::Value genMin(fir::FirOpBuilder &, mlir::Location,
894 llvm::ArrayRef<mlir::Value> args);
895
898mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc,
899 mlir::Type resultType, mlir::Value x, mlir::Value y);
900
903mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType,
904 mlir::Value x, mlir::Value y);
905
906} // namespace fir
907
908#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:2116
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:9659
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:9713
mlir::Value genPow(fir::FirOpBuilder &, mlir::Location, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:9726
mlir::Value genDivC(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type resultType, mlir::Value x, mlir::Value y)
Definition IntrinsicCall.cpp:9721
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:2138
ArgLoweringRule lowerIntrinsicArgumentAs(const IntrinsicArgumentLoweringRules &, unsigned position)
Definition IntrinsicCall.cpp:9684
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:9747
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:9697
mlir::Value genMax(fir::FirOpBuilder &, mlir::Location, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:9705
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:599
IntrinsicDummyArgument args[7]
There is no more than 7 non repeated arguments in Fortran intrinsics.
Definition IntrinsicCall.h:601
Definition IntrinsicCall.h:592
Entry into the tables describing how an intrinsic must be lowered.
Definition IntrinsicCall.h:789
Definition IntrinsicCall.h:607
bool outline
Definition IntrinsicCall.h:615
mlir::SymbolRefAttr getUnrestrictedIntrinsicSymbolRefAttr(llvm::StringRef name, mlir::FunctionType signature)
Definition IntrinsicCall.cpp:2644
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:2150
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:4822
std::pair< fir::ExtendedValue, bool > genIntrinsicCall(llvm::StringRef name, std::optional< mlir::Type > resultType, llvm::ArrayRef< fir::ExtendedValue > arg)
Definition IntrinsicCall.cpp:2334
decltype(&IntrinsicLibrary::genEtime) DualGenerator
The generator for intrinsic that has both function and subroutine form.
Definition IntrinsicCall.h:525
mlir::Value outlineInWrapper(GeneratorType, llvm::StringRef name, mlir::Type resultType, llvm::ArrayRef< mlir::Value > args)
Definition IntrinsicCall.cpp:2543
mlir::Value genRuntimeCall(llvm::StringRef name, mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2715
mlir::Value genQNan(mlir::Type resultType)
Generate a quiet NaN of a given floating point type.
Definition IntrinsicCall.cpp:5035
mlir::Value genConversion(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2723
mlir::Value genAbs(mlir::Type, llvm::ArrayRef< mlir::Value >)
Definition IntrinsicCall.cpp:2737
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:9568
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:2678
decltype(&IntrinsicLibrary::genAbs) ElementalGenerator
Definition IntrinsicCall.h:521
fir::ExtendedValue genCAssociatedCPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_PTR [, C_PTR])
Definition IntrinsicCall.cpp:3581
fir::ExtendedValue genCAssociatedCFunPtr(mlir::Type, llvm::ArrayRef< fir::ExtendedValue >)
C_ASSOCIATED (C_FUNPTR [, C_FUNPTR])
Definition IntrinsicCall.cpp:3574
void genRaiseExcept(int excepts, mlir::Value cond={})
Definition IntrinsicCall.cpp:5042
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:2349
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:9487
Definition IntrinsicCall.h:630
Definition IntrinsicCall.h:680
Definition IntrinsicCall.h:618