xref: /llvm-project/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp (revision 5a34e6fdceac40da3312d96273e4b5d767f4a481)
1 //===-- Intrinsics.cpp ----------------------------------------------------===//
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 #include "flang/Optimizer/Builder/Runtime/Intrinsics.h"
10 #include "flang/Optimizer/Builder/BoxValue.h"
11 #include "flang/Optimizer/Builder/FIRBuilder.h"
12 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
13 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
14 #include "flang/Parser/parse-tree.h"
15 #include "flang/Runtime/extensions.h"
16 #include "flang/Runtime/misc-intrinsic.h"
17 #include "flang/Runtime/pointer.h"
18 #include "flang/Runtime/random.h"
19 #include "flang/Runtime/stop.h"
20 #include "flang/Runtime/time-intrinsic.h"
21 #include "flang/Semantics/tools.h"
22 #include "llvm/Support/Debug.h"
23 #include <optional>
24 #include <signal.h>
25 
26 #define DEBUG_TYPE "flang-lower-runtime"
27 
28 using namespace Fortran::runtime;
29 
30 namespace {
31 /// Placeholder for real*16 version of RandomNumber Intrinsic
32 struct ForcedRandomNumberReal16 {
33   static constexpr const char *name = ExpandAndQuoteKey(RTNAME(RandomNumber16));
34   static constexpr fir::runtime::FuncTypeBuilderFunc getTypeModel() {
35     return [](mlir::MLIRContext *ctx) {
36       auto boxTy =
37           fir::runtime::getModel<const Fortran::runtime::Descriptor &>()(ctx);
38       auto strTy = fir::runtime::getModel<const char *>()(ctx);
39       auto intTy = fir::runtime::getModel<int>()(ctx);
40       ;
41       return mlir::FunctionType::get(ctx, {boxTy, strTy, intTy}, {});
42     };
43   }
44 };
45 } // namespace
46 
47 mlir::Value fir::runtime::genAssociated(fir::FirOpBuilder &builder,
48                                         mlir::Location loc, mlir::Value pointer,
49                                         mlir::Value target) {
50   mlir::func::FuncOp func =
51       fir::runtime::getRuntimeFunc<mkRTKey(PointerIsAssociatedWith)>(loc,
52                                                                      builder);
53   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
54       builder, loc, func.getFunctionType(), pointer, target);
55   return builder.create<fir::CallOp>(loc, func, args).getResult(0);
56 }
57 
58 mlir::Value fir::runtime::genCpuTime(fir::FirOpBuilder &builder,
59                                      mlir::Location loc) {
60   mlir::func::FuncOp func =
61       fir::runtime::getRuntimeFunc<mkRTKey(CpuTime)>(loc, builder);
62   return builder.create<fir::CallOp>(loc, func, std::nullopt).getResult(0);
63 }
64 
65 void fir::runtime::genDateAndTime(fir::FirOpBuilder &builder,
66                                   mlir::Location loc,
67                                   std::optional<fir::CharBoxValue> date,
68                                   std::optional<fir::CharBoxValue> time,
69                                   std::optional<fir::CharBoxValue> zone,
70                                   mlir::Value values) {
71   mlir::func::FuncOp callee =
72       fir::runtime::getRuntimeFunc<mkRTKey(DateAndTime)>(loc, builder);
73   mlir::FunctionType funcTy = callee.getFunctionType();
74   mlir::Type idxTy = builder.getIndexType();
75   mlir::Value zero;
76   auto splitArg = [&](std::optional<fir::CharBoxValue> arg, mlir::Value &buffer,
77                       mlir::Value &len) {
78     if (arg) {
79       buffer = arg->getBuffer();
80       len = arg->getLen();
81     } else {
82       if (!zero)
83         zero = builder.createIntegerConstant(loc, idxTy, 0);
84       buffer = zero;
85       len = zero;
86     }
87   };
88   mlir::Value dateBuffer;
89   mlir::Value dateLen;
90   splitArg(date, dateBuffer, dateLen);
91   mlir::Value timeBuffer;
92   mlir::Value timeLen;
93   splitArg(time, timeBuffer, timeLen);
94   mlir::Value zoneBuffer;
95   mlir::Value zoneLen;
96   splitArg(zone, zoneBuffer, zoneLen);
97 
98   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
99   mlir::Value sourceLine =
100       fir::factory::locationToLineNo(builder, loc, funcTy.getInput(7));
101 
102   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
103       builder, loc, funcTy, dateBuffer, dateLen, timeBuffer, timeLen,
104       zoneBuffer, zoneLen, sourceFile, sourceLine, values);
105   builder.create<fir::CallOp>(loc, callee, args);
106 }
107 
108 void fir::runtime::genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
109                             mlir::Value values, mlir::Value time) {
110   auto runtimeFunc = fir::runtime::getRuntimeFunc<mkRTKey(Etime)>(loc, builder);
111   mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType();
112 
113   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
114   mlir::Value sourceLine =
115       fir::factory::locationToLineNo(builder, loc, runtimeFuncTy.getInput(3));
116 
117   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
118       builder, loc, runtimeFuncTy, values, time, sourceFile, sourceLine);
119   builder.create<fir::CallOp>(loc, runtimeFunc, args);
120 }
121 
122 void fir::runtime::genFree(fir::FirOpBuilder &builder, mlir::Location loc,
123                            mlir::Value ptr) {
124   auto runtimeFunc = fir::runtime::getRuntimeFunc<mkRTKey(Free)>(loc, builder);
125   mlir::Type intPtrTy = builder.getIntPtrType();
126 
127   builder.create<fir::CallOp>(loc, runtimeFunc,
128                               builder.createConvert(loc, intPtrTy, ptr));
129 }
130 
131 mlir::Value fir::runtime::genGetGID(fir::FirOpBuilder &builder,
132                                     mlir::Location loc) {
133   auto runtimeFunc =
134       fir::runtime::getRuntimeFunc<mkRTKey(GetGID)>(loc, builder);
135 
136   return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
137 }
138 
139 mlir::Value fir::runtime::genGetUID(fir::FirOpBuilder &builder,
140                                     mlir::Location loc) {
141   auto runtimeFunc =
142       fir::runtime::getRuntimeFunc<mkRTKey(GetUID)>(loc, builder);
143 
144   return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
145 }
146 
147 mlir::Value fir::runtime::genMalloc(fir::FirOpBuilder &builder,
148                                     mlir::Location loc, mlir::Value size) {
149   auto runtimeFunc =
150       fir::runtime::getRuntimeFunc<mkRTKey(Malloc)>(loc, builder);
151   auto argTy = runtimeFunc.getArgumentTypes()[0];
152   return builder
153       .create<fir::CallOp>(loc, runtimeFunc,
154                            builder.createConvert(loc, argTy, size))
155       .getResult(0);
156 }
157 
158 void fir::runtime::genRandomInit(fir::FirOpBuilder &builder, mlir::Location loc,
159                                  mlir::Value repeatable,
160                                  mlir::Value imageDistinct) {
161   mlir::func::FuncOp func =
162       fir::runtime::getRuntimeFunc<mkRTKey(RandomInit)>(loc, builder);
163   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
164       builder, loc, func.getFunctionType(), repeatable, imageDistinct);
165   builder.create<fir::CallOp>(loc, func, args);
166 }
167 
168 void fir::runtime::genRandomNumber(fir::FirOpBuilder &builder,
169                                    mlir::Location loc, mlir::Value harvest) {
170   mlir::func::FuncOp func;
171   auto boxEleTy = fir::dyn_cast_ptrOrBoxEleTy(harvest.getType());
172   auto eleTy = fir::unwrapSequenceType(boxEleTy);
173   if (eleTy.isF128()) {
174     func = fir::runtime::getRuntimeFunc<ForcedRandomNumberReal16>(loc, builder);
175   } else {
176     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomNumber)>(loc, builder);
177   }
178 
179   mlir::FunctionType funcTy = func.getFunctionType();
180   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
181   mlir::Value sourceLine =
182       fir::factory::locationToLineNo(builder, loc, funcTy.getInput(2));
183   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
184       builder, loc, funcTy, harvest, sourceFile, sourceLine);
185   builder.create<fir::CallOp>(loc, func, args);
186 }
187 
188 void fir::runtime::genRandomSeed(fir::FirOpBuilder &builder, mlir::Location loc,
189                                  mlir::Value size, mlir::Value put,
190                                  mlir::Value get) {
191   bool sizeIsPresent =
192       !mlir::isa_and_nonnull<fir::AbsentOp>(size.getDefiningOp());
193   bool putIsPresent =
194       !mlir::isa_and_nonnull<fir::AbsentOp>(put.getDefiningOp());
195   bool getIsPresent =
196       !mlir::isa_and_nonnull<fir::AbsentOp>(get.getDefiningOp());
197   mlir::func::FuncOp func;
198   int staticArgCount = sizeIsPresent + putIsPresent + getIsPresent;
199   if (staticArgCount == 0) {
200     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedDefaultPut)>(loc,
201                                                                        builder);
202     builder.create<fir::CallOp>(loc, func);
203     return;
204   }
205   mlir::FunctionType funcTy;
206   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
207   mlir::Value sourceLine;
208   mlir::Value argBox;
209   llvm::SmallVector<mlir::Value> args;
210   if (staticArgCount > 1) {
211     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeed)>(loc, builder);
212     funcTy = func.getFunctionType();
213     sourceLine =
214         fir::factory::locationToLineNo(builder, loc, funcTy.getInput(4));
215     args = fir::runtime::createArguments(builder, loc, funcTy, size, put, get,
216                                          sourceFile, sourceLine);
217     builder.create<fir::CallOp>(loc, func, args);
218     return;
219   }
220   if (sizeIsPresent) {
221     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedSize)>(loc, builder);
222     argBox = size;
223   } else if (putIsPresent) {
224     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedPut)>(loc, builder);
225     argBox = put;
226   } else {
227     func = fir::runtime::getRuntimeFunc<mkRTKey(RandomSeedGet)>(loc, builder);
228     argBox = get;
229   }
230   funcTy = func.getFunctionType();
231   sourceLine = fir::factory::locationToLineNo(builder, loc, funcTy.getInput(2));
232   args = fir::runtime::createArguments(builder, loc, funcTy, argBox, sourceFile,
233                                        sourceLine);
234   builder.create<fir::CallOp>(loc, func, args);
235 }
236 
237 /// generate rename runtime call
238 void fir::runtime::genRename(fir::FirOpBuilder &builder, mlir::Location loc,
239                              mlir::Value path1, mlir::Value path2,
240                              mlir::Value status) {
241   auto runtimeFunc =
242       fir::runtime::getRuntimeFunc<mkRTKey(Rename)>(loc, builder);
243   mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType();
244 
245   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
246   mlir::Value sourceLine =
247       fir::factory::locationToLineNo(builder, loc, runtimeFuncTy.getInput(4));
248 
249   llvm::SmallVector<mlir::Value> args =
250       fir::runtime::createArguments(builder, loc, runtimeFuncTy, path1, path2,
251                                     status, sourceFile, sourceLine);
252   builder.create<fir::CallOp>(loc, runtimeFunc, args);
253 }
254 
255 /// generate runtime call to transfer intrinsic with no size argument
256 void fir::runtime::genTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
257                                mlir::Value resultBox, mlir::Value sourceBox,
258                                mlir::Value moldBox) {
259 
260   mlir::func::FuncOp func =
261       fir::runtime::getRuntimeFunc<mkRTKey(Transfer)>(loc, builder);
262   mlir::FunctionType fTy = func.getFunctionType();
263   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
264   mlir::Value sourceLine =
265       fir::factory::locationToLineNo(builder, loc, fTy.getInput(4));
266   llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
267       builder, loc, fTy, resultBox, sourceBox, moldBox, sourceFile, sourceLine);
268   builder.create<fir::CallOp>(loc, func, args);
269 }
270 
271 /// generate runtime call to transfer intrinsic with size argument
272 void fir::runtime::genTransferSize(fir::FirOpBuilder &builder,
273                                    mlir::Location loc, mlir::Value resultBox,
274                                    mlir::Value sourceBox, mlir::Value moldBox,
275                                    mlir::Value size) {
276   mlir::func::FuncOp func =
277       fir::runtime::getRuntimeFunc<mkRTKey(TransferSize)>(loc, builder);
278   mlir::FunctionType fTy = func.getFunctionType();
279   mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
280   mlir::Value sourceLine =
281       fir::factory::locationToLineNo(builder, loc, fTy.getInput(4));
282   llvm::SmallVector<mlir::Value> args =
283       fir::runtime::createArguments(builder, loc, fTy, resultBox, sourceBox,
284                                     moldBox, sourceFile, sourceLine, size);
285   builder.create<fir::CallOp>(loc, func, args);
286 }
287 
288 /// generate system_clock runtime call/s
289 /// all intrinsic arguments are optional and may appear here as mlir::Value{}
290 void fir::runtime::genSystemClock(fir::FirOpBuilder &builder,
291                                   mlir::Location loc, mlir::Value count,
292                                   mlir::Value rate, mlir::Value max) {
293   auto makeCall = [&](mlir::func::FuncOp func, mlir::Value arg) {
294     mlir::Type type = arg.getType();
295     fir::IfOp ifOp{};
296     const bool isOptionalArg =
297         fir::valueHasFirAttribute(arg, fir::getOptionalAttrName());
298     if (mlir::dyn_cast<fir::PointerType>(type) ||
299         mlir::dyn_cast<fir::HeapType>(type)) {
300       // Check for a disassociated pointer or an unallocated allocatable.
301       assert(!isOptionalArg && "invalid optional argument");
302       ifOp = builder.create<fir::IfOp>(loc, builder.genIsNotNullAddr(loc, arg),
303                                        /*withElseRegion=*/false);
304     } else if (isOptionalArg) {
305       ifOp = builder.create<fir::IfOp>(
306           loc, builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), arg),
307           /*withElseRegion=*/false);
308     }
309     if (ifOp)
310       builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
311     mlir::Type kindTy = func.getFunctionType().getInput(0);
312     int integerKind = 8;
313     if (auto intType =
314             mlir::dyn_cast<mlir::IntegerType>(fir::unwrapRefType(type)))
315       integerKind = intType.getWidth() / 8;
316     mlir::Value kind = builder.createIntegerConstant(loc, kindTy, integerKind);
317     mlir::Value res =
318         builder.create<fir::CallOp>(loc, func, mlir::ValueRange{kind})
319             .getResult(0);
320     mlir::Value castRes =
321         builder.createConvert(loc, fir::dyn_cast_ptrEleTy(type), res);
322     builder.create<fir::StoreOp>(loc, castRes, arg);
323     if (ifOp)
324       builder.setInsertionPointAfter(ifOp);
325   };
326   using fir::runtime::getRuntimeFunc;
327   if (count)
328     makeCall(getRuntimeFunc<mkRTKey(SystemClockCount)>(loc, builder), count);
329   if (rate)
330     makeCall(getRuntimeFunc<mkRTKey(SystemClockCountRate)>(loc, builder), rate);
331   if (max)
332     makeCall(getRuntimeFunc<mkRTKey(SystemClockCountMax)>(loc, builder), max);
333 }
334 
335 // CALL SIGNAL(NUMBER, HANDLER [, STATUS])
336 // The definition of the SIGNAL intrinsic allows HANDLER to be a function
337 // pointer or an integer. STATUS can be dynamically optional
338 void fir::runtime::genSignal(fir::FirOpBuilder &builder, mlir::Location loc,
339                              mlir::Value number, mlir::Value handler,
340                              mlir::Value status) {
341   assert(mlir::isa<mlir::IntegerType>(number.getType()));
342   mlir::Type int64 = builder.getIntegerType(64);
343   number = builder.create<fir::ConvertOp>(loc, int64, number);
344 
345   mlir::Type handlerUnwrappedTy = fir::unwrapRefType(handler.getType());
346   if (mlir::isa_and_nonnull<mlir::IntegerType>(handlerUnwrappedTy)) {
347     // pass the integer as a function pointer like one would to signal(2)
348     handler = builder.create<fir::LoadOp>(loc, handler);
349     mlir::Type fnPtrTy = fir::LLVMPointerType::get(
350         mlir::FunctionType::get(handler.getContext(), {}, {}));
351     handler = builder.create<fir::ConvertOp>(loc, fnPtrTy, handler);
352   } else {
353     assert(mlir::isa<fir::BoxProcType>(handler.getType()));
354     handler = builder.create<fir::BoxAddrOp>(loc, handler);
355   }
356 
357   mlir::func::FuncOp func{
358       fir::runtime::getRuntimeFunc<mkRTKey(Signal)>(loc, builder)};
359   mlir::Value stat =
360       builder.create<fir::CallOp>(loc, func, mlir::ValueRange{number, handler})
361           ->getResult(0);
362 
363   // return status code via status argument (if present)
364   if (status) {
365     assert(mlir::isa<mlir::IntegerType>(fir::unwrapRefType(status.getType())));
366     // status might be dynamically optional, so test if it is present
367     mlir::Value isPresent =
368         builder.create<IsPresentOp>(loc, builder.getI1Type(), status);
369     builder.genIfOp(loc, /*results=*/{}, isPresent, /*withElseRegion=*/false)
370         .genThen([&]() {
371           stat = builder.create<fir::ConvertOp>(
372               loc, fir::unwrapRefType(status.getType()), stat);
373           builder.create<fir::StoreOp>(loc, stat, status);
374         })
375         .end();
376   }
377 }
378 
379 void fir::runtime::genSleep(fir::FirOpBuilder &builder, mlir::Location loc,
380                             mlir::Value seconds) {
381   mlir::Type int64 = builder.getIntegerType(64);
382   seconds = builder.create<fir::ConvertOp>(loc, int64, seconds);
383   mlir::func::FuncOp func{
384       fir::runtime::getRuntimeFunc<mkRTKey(Sleep)>(loc, builder)};
385   builder.create<fir::CallOp>(loc, func, seconds);
386 }
387 
388 /// generate chdir runtime call
389 mlir::Value fir::runtime::genChdir(fir::FirOpBuilder &builder,
390                                    mlir::Location loc, mlir::Value name) {
391   mlir::func::FuncOp func{
392       fir::runtime::getRuntimeFunc<mkRTKey(Chdir)>(loc, builder)};
393   llvm::SmallVector<mlir::Value> args =
394       fir::runtime::createArguments(builder, loc, func.getFunctionType(), name);
395   return builder.create<fir::CallOp>(loc, func, args).getResult(0);
396 }
397