Skip to content

Commit 92d6533

Browse files
jeanPerierschweitzpgi
authored andcommitted
Lower date_and_time intrinsic (only date for now)
1 parent accd5eb commit 92d6533

File tree

8 files changed

+226
-35
lines changed

8 files changed

+226
-35
lines changed

flang/include/flang/Lower/IntrinsicCall.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define FORTRAN_LOWER_INTRINSICCALL_H
1111

1212
#include "flang/Lower/FIRBuilder.h"
13+
#include "llvm/ADT/Optional.h"
1314

1415
namespace fir {
1516
class ExtendedValue;
@@ -32,7 +33,8 @@ namespace Fortran::lower {
3233
/// with arguments \p args and expected result type \p resultType.
3334
/// Returned mlir::Value is the returned Fortran intrinsic value.
3435
fir::ExtendedValue genIntrinsicCall(FirOpBuilder &, mlir::Location,
35-
llvm::StringRef name, mlir::Type resultType,
36+
llvm::StringRef name,
37+
llvm::Optional<mlir::Type> resultType,
3638
llvm::ArrayRef<fir::ExtendedValue> args);
3739

3840
/// Get SymbolRefAttr of runtime (or wrapper function containing inlined

flang/include/flang/Lower/Runtime.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,19 @@
2020
#ifndef FORTRAN_LOWER_RUNTIME_H
2121
#define FORTRAN_LOWER_RUNTIME_H
2222

23+
namespace llvm {
24+
template <typename T>
25+
class Optional;
26+
}
27+
28+
namespace mlir {
29+
class Location;
30+
}
31+
32+
namespace fir {
33+
class CharBoxValue;
34+
}
35+
2336
namespace Fortran {
2437

2538
namespace parser {
@@ -38,6 +51,7 @@ struct UnlockStmt;
3851
namespace lower {
3952

4053
class AbstractConverter;
54+
class FirOpBuilder;
4155

4256
// Lowering of Fortran statement related runtime (other than IO and maths)
4357

@@ -55,6 +69,9 @@ void genSyncTeamStatement(AbstractConverter &, const parser::SyncTeamStmt &);
5569
void genUnlockStatement(AbstractConverter &, const parser::UnlockStmt &);
5670
void genPauseStatement(AbstractConverter &, const parser::PauseStmt &);
5771

72+
void genDateAndTime(FirOpBuilder &, mlir::Location,
73+
llvm::Optional<fir::CharBoxValue> date);
74+
5875
} // namespace lower
5976
} // namespace Fortran
6077

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,9 +1284,10 @@ class ExprLowering {
12841284
fir::ExtendedValue
12851285
genIntrinsicRef(const Fortran::evaluate::ProcedureRef &procRef,
12861286
const Fortran::evaluate::SpecificIntrinsic &intrinsic,
1287-
mlir::ArrayRef<mlir::Type> resultType) {
1288-
if (resultType.size() != 1)
1289-
TODO(); // Intrinsic subroutine
1287+
mlir::ArrayRef<mlir::Type> resultTypes) {
1288+
llvm::Optional<mlir::Type> resultType;
1289+
if (resultTypes.size() == 1)
1290+
resultType = resultTypes[0];
12901291

12911292
llvm::SmallVector<fir::ExtendedValue, 2> operands;
12921293
// Lower arguments
@@ -1304,8 +1305,8 @@ class ExprLowering {
13041305
}
13051306
// Let the intrinsic library lower the intrinsic procedure call
13061307
llvm::StringRef name = intrinsic.name;
1307-
return Fortran::lower::genIntrinsicCall(builder, getLoc(), name,
1308-
resultType[0], operands);
1308+
return Fortran::lower::genIntrinsicCall(builder, getLoc(), name, resultType,
1309+
operands);
13091310
}
13101311

13111312
template <typename A>
@@ -1363,7 +1364,7 @@ class ExprLowering {
13631364
genProcedureRef(const Fortran::evaluate::ProcedureRef &procRef,
13641365
mlir::ArrayRef<mlir::Type> resultType) {
13651366
if (const auto *intrinsic = procRef.proc().GetSpecificIntrinsic())
1366-
return genIntrinsicRef(procRef, *intrinsic, resultType[0]);
1367+
return genIntrinsicRef(procRef, *intrinsic, resultType);
13671368

13681369
if (isStatementFunctionCall(procRef))
13691370
return genStmtFunctionRef(procRef, resultType);

flang/lib/Lower/IntrinsicCall.cpp

Lines changed: 102 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ struct IntrinsicLibrary {
183183
/// Generate FIR for call to Fortran intrinsic \p name with arguments \p arg
184184
/// and expected result type \p resultType.
185185
fir::ExtendedValue genIntrinsicCall(llvm::StringRef name,
186-
mlir::Type resultType,
186+
llvm::Optional<mlir::Type> resultType,
187187
llvm::ArrayRef<fir::ExtendedValue> arg);
188188

189189
/// Search a runtime function that is associated to the generic intrinsic name
@@ -209,6 +209,7 @@ struct IntrinsicLibrary {
209209
mlir::Value genAnint(mlir::Type, llvm::ArrayRef<mlir::Value>);
210210
mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
211211
mlir::Value genConjg(mlir::Type, llvm::ArrayRef<mlir::Value>);
212+
void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
212213
mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
213214
mlir::Value genDprod(mlir::Type, llvm::ArrayRef<mlir::Value>);
214215
template <Extremum, ExtremumBehavior>
@@ -233,7 +234,9 @@ struct IntrinsicLibrary {
233234
/// generate the related code.
234235
using ElementalGenerator = decltype(&IntrinsicLibrary::genAbs);
235236
using ExtendedGenerator = decltype(&IntrinsicLibrary::genLenTrim);
236-
using Generator = std::variant<ElementalGenerator, ExtendedGenerator>;
237+
using SubroutineGenerator = decltype(&IntrinsicLibrary::genDateAndTime);
238+
using Generator =
239+
std::variant<ElementalGenerator, ExtendedGenerator, SubroutineGenerator>;
237240

238241
/// All generators can be outlined. This will build a function named
239242
/// "fir."+ <generic name> + "." + <result type code> and generate the
@@ -269,6 +272,9 @@ struct IntrinsicLibrary {
269272
mlir::Value invokeGenerator(ExtendedGenerator generator,
270273
mlir::Type resultType,
271274
llvm::ArrayRef<mlir::Value> args);
275+
mlir::Value invokeGenerator(SubroutineGenerator generator,
276+
mlir::Type resultType,
277+
llvm::ArrayRef<mlir::Value> args);
272278

273279
/// Get pointer to unrestricted intrinsic. Generate the related unrestricted
274280
/// intrinsic if it is not defined yet.
@@ -292,6 +298,7 @@ struct IntrinsicHandler {
292298
/// more readable.
293299
bool outline = false;
294300
};
301+
295302
using I = IntrinsicLibrary;
296303
static constexpr IntrinsicHandler handlers[]{
297304
{"abs", &I::genAbs},
@@ -302,6 +309,7 @@ static constexpr IntrinsicHandler handlers[]{
302309
{"ceiling", &I::genCeiling},
303310
{"char", &I::genConversion},
304311
{"conjg", &I::genConjg},
312+
{"date_and_time", &I::genDateAndTime},
305313
{"dim", &I::genDim},
306314
{"dble", &I::genConversion},
307315
{"dprod", &I::genDprod},
@@ -761,24 +769,71 @@ IntrinsicLibrary::genElementalCall<IntrinsicLibrary::ExtendedGenerator>(
761769
return std::invoke(generator, *this, resultType, args);
762770
}
763771

772+
static fir::ExtendedValue
773+
invokeHanlder(IntrinsicLibrary::ElementalGenerator generator,
774+
const IntrinsicHandler &handler,
775+
llvm::Optional<mlir::Type> resultType,
776+
llvm::ArrayRef<fir::ExtendedValue> args, bool outline,
777+
IntrinsicLibrary &lib) {
778+
assert(resultType && "expect elemental intrinsic to be functions");
779+
return lib.genElementalCall(generator, handler.name, *resultType, args,
780+
outline);
781+
}
782+
783+
static fir::ExtendedValue
784+
invokeHanlder(IntrinsicLibrary::ExtendedGenerator generator,
785+
const IntrinsicHandler &handler,
786+
llvm::Optional<mlir::Type> resultType,
787+
llvm::ArrayRef<fir::ExtendedValue> args, bool outline,
788+
IntrinsicLibrary &lib) {
789+
assert(resultType && "expect intrinsic function");
790+
if (handler.isElemental)
791+
return lib.genElementalCall(generator, handler.name, *resultType, args,
792+
outline);
793+
if (outline)
794+
return lib.outlineInWrapper(generator, handler.name, *resultType, args);
795+
return std::invoke(generator, lib, *resultType, args);
796+
}
797+
static fir::ExtendedValue
798+
invokeHanlder(IntrinsicLibrary::SubroutineGenerator generator,
799+
const IntrinsicHandler &handler,
800+
llvm::Optional<mlir::Type> resultType,
801+
llvm::ArrayRef<fir::ExtendedValue> args, bool outline,
802+
IntrinsicLibrary &lib) {
803+
// TODO
804+
// if (outline)
805+
// return outlineInWrapper(generator, handler.name, *resultType, args);
806+
std::invoke(generator, lib, args);
807+
return mlir::Value{};
808+
}
809+
810+
/// Many intrinsics are not yet lowered, provide a clear error message to user
811+
/// instead of hitting harder to understand asserts.
812+
static void crashOnMissingIntrinsic(mlir::Location loc, llvm::StringRef name) {
813+
mlir::emitError(loc,
814+
"TODO: missing intrinsic lowering: " + llvm::Twine(name));
815+
exit(1);
816+
}
817+
764818
fir::ExtendedValue
765-
IntrinsicLibrary::genIntrinsicCall(llvm::StringRef name, mlir::Type resultType,
819+
IntrinsicLibrary::genIntrinsicCall(llvm::StringRef name,
820+
llvm::Optional<mlir::Type> resultType,
766821
llvm::ArrayRef<fir::ExtendedValue> args) {
767822
for (auto &handler : handlers)
768823
if (name == handler.name) {
769824
bool outline = handler.outline || outlineAllIntrinsics;
770-
if (const auto *elementalGenerator =
771-
std::get_if<ElementalGenerator>(&handler.generator))
772-
return genElementalCall(*elementalGenerator, name, resultType, args,
773-
outline);
774-
const auto &generator = std::get<ExtendedGenerator>(handler.generator);
775-
if (handler.isElemental)
776-
return genElementalCall(generator, name, resultType, args, outline);
777-
if (outline)
778-
return outlineInWrapper(generator, name, resultType, args);
779-
return std::invoke(generator, *this, resultType, args);
825+
return std::visit(
826+
[&](auto &generator) -> fir::ExtendedValue {
827+
return invokeHanlder(generator, handler, resultType, args, outline,
828+
*this);
829+
},
830+
handler.generator);
780831
}
781832

833+
if (!resultType)
834+
// Subroutine should have a handler, they are likely missing for now.
835+
crashOnMissingIntrinsic(loc, name);
836+
782837
// Try the runtime if no special handler was defined for the
783838
// intrinsic being called. Maths runtime only has numerical elemental.
784839
// No optional arguments are expected at this point, the code will
@@ -788,20 +843,17 @@ IntrinsicLibrary::genIntrinsicCall(llvm::StringRef name, mlir::Type resultType,
788843
llvm::SmallVector<mlir::Value, 2> mlirArgs;
789844
for (const auto &extendedVal : args) {
790845
auto val = toValue(extendedVal, builder, loc);
791-
if (!val) {
846+
if (!val)
792847
// If an absent optional gets there, most likely its handler has just
793848
// not yet been defined.
794-
mlir::emitError(loc,
795-
"TODO: missing intrinsic lowering: " + llvm::Twine(name));
796-
exit(1);
797-
}
849+
crashOnMissingIntrinsic(loc, name);
798850
mlirArgs.emplace_back(val);
799851
}
800852
mlir::FunctionType soughtFuncType =
801-
getFunctionType(resultType, mlirArgs, builder);
853+
getFunctionType(*resultType, mlirArgs, builder);
802854

803855
auto runtimeCallGenerator = getRuntimeCallGenerator(name, soughtFuncType);
804-
return genElementalCall(runtimeCallGenerator, name, resultType, args,
856+
return genElementalCall(runtimeCallGenerator, name, *resultType, args,
805857
/* outline */ true);
806858
}
807859

@@ -830,14 +882,22 @@ IntrinsicLibrary::invokeGenerator(ExtendedGenerator generator,
830882
return toValue(extendedResult, builder, loc);
831883
}
832884

885+
mlir::Value
886+
IntrinsicLibrary::invokeGenerator(SubroutineGenerator generator,
887+
mlir::Type resultType,
888+
llvm::ArrayRef<mlir::Value> args) {
889+
llvm::SmallVector<fir::ExtendedValue, 2> extendedArgs;
890+
for (auto arg : args)
891+
extendedArgs.emplace_back(toExtendedValue(arg, builder, loc));
892+
std::invoke(generator, *this, extendedArgs);
893+
return mlir::Value{};
894+
}
895+
833896
template <typename GeneratorType>
834897
mlir::FuncOp IntrinsicLibrary::getWrapper(GeneratorType generator,
835898
llvm::StringRef name,
836899
mlir::FunctionType funcType,
837900
bool loadRefArguments) {
838-
assert(funcType.getNumResults() == 1 &&
839-
"expect one result for intrinsic functions");
840-
auto resultType = funcType.getResult(0);
841901
std::string wrapperName = fir::mangleIntrinsicProcedure(name, funcType);
842902
auto function = builder.getNamedFunction(wrapperName);
843903
if (!function) {
@@ -868,6 +928,9 @@ mlir::FuncOp IntrinsicLibrary::getWrapper(GeneratorType generator,
868928
}
869929

870930
IntrinsicLibrary localLib{*localBuilder, localLoc};
931+
mlir::Type resultType;
932+
if (funcType.getNumResults() == 1)
933+
resultType = funcType.getResult(0);
871934
auto result =
872935
localLib.invokeGenerator(generator, resultType, localArguments);
873936
localBuilder->create<mlir::ReturnOp>(localLoc, result);
@@ -1101,6 +1164,20 @@ mlir::Value IntrinsicLibrary::genConjg(mlir::Type resultType,
11011164
cplx, negImag, /*isImagPart=*/true);
11021165
}
11031166

1167+
// DATE_AND_TIME
1168+
void IntrinsicLibrary::genDateAndTime(llvm::ArrayRef<fir::ExtendedValue> args) {
1169+
assert(args.size() == 4 && "date_and_time has 4 args");
1170+
llvm::Optional<fir::CharBoxValue> date;
1171+
if (auto *charBox = args[0].getCharBox())
1172+
date = *charBox;
1173+
for (auto i = 1; i < 4; ++i)
1174+
if (fir::getBase(args[i]))
1175+
llvm::errs() << "TODO: lowering of DATE_AND_TIME arguments other than "
1176+
"DATE not yet implemented\n";
1177+
1178+
Fortran::lower::genDateAndTime(builder, loc, date);
1179+
}
1180+
11041181
// DIM
11051182
mlir::Value IntrinsicLibrary::genDim(mlir::Type resultType,
11061183
llvm::ArrayRef<mlir::Value> args) {
@@ -1153,7 +1230,7 @@ mlir::Value IntrinsicLibrary::genIAnd(mlir::Type resultType,
11531230
mlir::Value IntrinsicLibrary::genIchar(mlir::Type resultType,
11541231
llvm::ArrayRef<mlir::Value> args) {
11551232
// There can be an optional kind in second argument.
1156-
assert(args.size() >= 1 && args.size() <= 2);
1233+
assert(args.size() == 2);
11571234

11581235
auto arg = args[0];
11591236
auto argTy = arg.getType();
@@ -1360,7 +1437,7 @@ mlir::Value IntrinsicLibrary::genExtremum(mlir::Type,
13601437
fir::ExtendedValue
13611438
Fortran::lower::genIntrinsicCall(Fortran::lower::FirOpBuilder &builder,
13621439
mlir::Location loc, llvm::StringRef name,
1363-
mlir::Type resultType,
1440+
llvm::Optional<mlir::Type> resultType,
13641441
llvm::ArrayRef<fir::ExtendedValue> args) {
13651442
return IntrinsicLibrary{builder, loc}.genIntrinsicCall(name, resultType,
13661443
args);

flang/lib/Lower/Runtime.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,23 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Lower/Runtime.h"
10+
#include "../runtime/clock.h"
1011
#include "../runtime/stop.h"
1112
#include "RTBuilder.h"
1213
#include "flang/Lower/Bridge.h"
1314
#include "flang/Lower/FIRBuilder.h"
15+
#include "flang/Lower/Support/BoxValue.h"
1416
#include "flang/Parser/parse-tree.h"
1517
#include "flang/Semantics/tools.h"
1618
#include "llvm/ADT/SmallVector.h"
1719

20+
using namespace Fortran::runtime;
1821
#define mkRTKey(X) mkKey(RTNAME(X))
1922

20-
static constexpr std::tuple<mkRTKey(StopStatementText),
23+
static constexpr std::tuple<mkRTKey(DateAndTime), mkRTKey(FailImageStatement),
24+
mkRTKey(PauseStatement),
2125
mkRTKey(ProgramEndStatement),
22-
mkRTKey(StopStatement), mkRTKey(FailImageStatement),
23-
mkRTKey(PauseStatement)>
26+
mkRTKey(StopStatement), mkRTKey(StopStatementText)>
2427
newRTTable;
2528

2629
template <typename A>
@@ -177,3 +180,26 @@ void Fortran::lower::genPauseStatement(
177180
auto callee = genRuntimeFunction<mkRTKey(PauseStatement)>(loc, bldr);
178181
bldr.create<fir::CallOp>(loc, callee, llvm::None);
179182
}
183+
184+
void Fortran::lower::genDateAndTime(Fortran::lower::FirOpBuilder &builder,
185+
mlir::Location loc,
186+
llvm::Optional<fir::CharBoxValue> date) {
187+
auto callee = genRuntimeFunction<mkRTKey(DateAndTime)>(loc, builder);
188+
mlir::Type idxTy = builder.getIndexType();
189+
mlir::Value dateBuffer;
190+
mlir::Value dateLen;
191+
if (date) {
192+
dateBuffer = date->getBuffer();
193+
dateLen = date->getLen();
194+
} else {
195+
auto zero = builder.createIntegerConstant(loc, idxTy, 0);
196+
dateBuffer = zero;
197+
dateLen = zero;
198+
}
199+
llvm::SmallVector<mlir::Value, 2> args{dateBuffer, dateLen};
200+
llvm::SmallVector<mlir::Value, 2> operands;
201+
for (const auto &op : llvm::zip(args, callee.getType().getInputs()))
202+
operands.emplace_back(
203+
builder.convertWithSemantics(loc, std::get<1>(op), std::get<0>(op)));
204+
builder.create<fir::CallOp>(loc, callee, operands);
205+
}

flang/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_flang_library(FortranRuntime
2929
ISO_Fortran_binding.cpp
3030
allocatable.cpp
3131
buffer.cpp
32+
clock.cpp
3233
character.cpp
3334
connection.cpp
3435
derived-type.cpp

0 commit comments

Comments
 (0)