diff --git a/flang/include/flang/Lower/Runtime.h b/flang/include/flang/Lower/Runtime.h --- a/flang/include/flang/Lower/Runtime.h +++ b/flang/include/flang/Lower/Runtime.h @@ -16,12 +16,18 @@ #ifndef FORTRAN_LOWER_RUNTIME_H #define FORTRAN_LOWER_RUNTIME_H +namespace llvm { +template +class Optional; +} + namespace mlir { class Location; class Value; } // namespace mlir namespace fir { +class CharBoxValue; class FirOpBuilder; } // namespace fir @@ -63,6 +69,12 @@ mlir::Value genAssociated(fir::FirOpBuilder &, mlir::Location, mlir::Value pointer, mlir::Value target); +mlir::Value genCpuTime(fir::FirOpBuilder &, mlir::Location); +void genDateAndTime(fir::FirOpBuilder &, mlir::Location, + llvm::Optional date, + llvm::Optional time, + llvm::Optional zone, mlir::Value values); + void genRandomInit(fir::FirOpBuilder &, mlir::Location, mlir::Value repeatable, mlir::Value imageDistinct); void genRandomNumber(fir::FirOpBuilder &, mlir::Location, mlir::Value harvest); diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -243,6 +243,8 @@ fir::ExtendedValue genAssociated(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genChar(mlir::Type, llvm::ArrayRef); + void genCpuTime(llvm::ArrayRef); + void genDateAndTime(llvm::ArrayRef); template mlir::Value genExtremum(mlir::Type, llvm::ArrayRef); /// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments @@ -361,6 +363,17 @@ {{{"pointer", asInquired}, {"target", asInquired}}}, /*isElemental=*/false}, {"char", &I::genChar}, + {"cpu_time", + &I::genCpuTime, + {{{"time", asAddr}}}, + /*isElemental=*/false}, + {"date_and_time", + &I::genDateAndTime, + {{{"date", asAddr, handleDynamicOptional}, + {"time", asAddr, handleDynamicOptional}, + {"zone", asAddr, handleDynamicOptional}, + {"values", asBox, handleDynamicOptional}}}, + /*isElemental=*/false}, {"iand", &I::genIand}, {"min", &I::genExtremum}, {"random_init", @@ -1294,6 +1307,34 @@ return fir::CharBoxValue{cast, len}; } +// CPU_TIME +void IntrinsicLibrary::genCpuTime(llvm::ArrayRef args) { + assert(args.size() == 1); + const mlir::Value *arg = args[0].getUnboxed(); + assert(arg && "nonscalar cpu_time argument"); + mlir::Value res1 = Fortran::lower::genCpuTime(builder, loc); + mlir::Value res2 = + builder.createConvert(loc, fir::dyn_cast_ptrEleTy(arg->getType()), res1); + builder.create(loc, res2, *arg); +} + +// DATE_AND_TIME +void IntrinsicLibrary::genDateAndTime(llvm::ArrayRef args) { + assert(args.size() == 4 && "date_and_time has 4 args"); + llvm::SmallVector> charArgs(3); + for (unsigned i = 0; i < 3; ++i) + if (const fir::CharBoxValue *charBox = args[i].getCharBox()) + charArgs[i] = *charBox; + + mlir::Value values = fir::getBase(args[3]); + if (!values) + values = builder.create( + loc, fir::BoxType::get(builder.getNoneType())); + + Fortran::lower::genDateAndTime(builder, loc, charArgs[0], charArgs[1], + charArgs[2], values); +} + // IAND mlir::Value IntrinsicLibrary::genIand(mlir::Type resultType, llvm::ArrayRef args) { diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp --- a/flang/lib/Lower/Runtime.cpp +++ b/flang/lib/Lower/Runtime.cpp @@ -16,6 +16,7 @@ #include "flang/Runtime/pointer.h" #include "flang/Runtime/random.h" #include "flang/Runtime/stop.h" +#include "flang/Runtime/time-intrinsic.h" #include "flang/Semantics/tools.h" #include "llvm/Support/Debug.h" @@ -127,6 +128,56 @@ return builder.create(loc, func, args).getResult(0); } +mlir::Value Fortran::lower::genCpuTime(fir::FirOpBuilder &builder, + mlir::Location loc) { + mlir::FuncOp func = + fir::runtime::getRuntimeFunc(loc, builder); + return builder.create(loc, func, llvm::None).getResult(0); +} + +void Fortran::lower::genDateAndTime(fir::FirOpBuilder &builder, + mlir::Location loc, + llvm::Optional date, + llvm::Optional time, + llvm::Optional zone, + mlir::Value values) { + mlir::FuncOp callee = + fir::runtime::getRuntimeFunc(loc, builder); + mlir::FunctionType funcTy = callee.getType(); + mlir::Type idxTy = builder.getIndexType(); + mlir::Value zero; + auto splitArg = [&](llvm::Optional arg, + mlir::Value &buffer, mlir::Value &len) { + if (arg) { + buffer = arg->getBuffer(); + len = arg->getLen(); + } else { + if (!zero) + zero = builder.createIntegerConstant(loc, idxTy, 0); + buffer = zero; + len = zero; + } + }; + mlir::Value dateBuffer; + mlir::Value dateLen; + splitArg(date, dateBuffer, dateLen); + mlir::Value timeBuffer; + mlir::Value timeLen; + splitArg(time, timeBuffer, timeLen); + mlir::Value zoneBuffer; + mlir::Value zoneLen; + splitArg(zone, zoneBuffer, zoneLen); + + mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc); + mlir::Value sourceLine = + fir::factory::locationToLineNo(builder, loc, funcTy.getInput(7)); + + llvm::SmallVector args = fir::runtime::createArguments( + builder, loc, funcTy, dateBuffer, dateLen, timeBuffer, timeLen, + zoneBuffer, zoneLen, sourceFile, sourceLine, values); + builder.create(loc, callee, args); +} + void Fortran::lower::genRandomInit(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value repeatable, mlir::Value imageDistinct) { diff --git a/flang/test/Lower/Intrinsics/cpu_time.f90 b/flang/test/Lower/Intrinsics/cpu_time.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/Intrinsics/cpu_time.f90 @@ -0,0 +1,11 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: cpu_time_test +subroutine cpu_time_test(t) + real :: t + ! CHECK: %[[result64:[0-9]+]] = fir.call @_FortranACpuTime() : () -> f64 + ! CHECK: %[[result32:[0-9]+]] = fir.convert %[[result64]] : (f64) -> f32 + ! CHECK: fir.store %[[result32]] to %arg0 : !fir.ref + call cpu_time(t) + end subroutine + \ No newline at end of file diff --git a/flang/test/Lower/Intrinsics/date_and_time.f90 b/flang/test/Lower/Intrinsics/date_and_time.f90 new file mode 100644