Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions flang/docs/Intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,33 @@ program rename_proc
end program rename_proc
```

### Non-Standard Intrinsics: SECNDS
#### Description
`SECNDS(refTime)` returns the number of seconds since midnight minus a user-supplied reference time `refTime`. If the difference is negative (i.e., the current time is past midnight and refTime was from the previous day), the result wraps around midnight to yield a positive value.

#### Usage and Info
- **Standard:** GNU extension
- **Class:** function
- **Syntax:** result = `SECNDS(refTime)`
- **Arguments:**

| ARGUMENT | INTENT | TYPE | KIND | Description |
|-----------|--------|---------------|-------------------------|------------------------------------------|
| `refTime` | `IN` | `REAL, scalar`| REAL(KIND=4), required | Reference time in seconds since midnight |

- **Return Value:** REAL(KIND=4), scalar — seconds elapsed since `refTime`.
- **Purity:** Impure. SECNDS references the system clock and may not be invoked from a PURE procedure.

#### Example
```Fortran
PROGRAM example_secnds
REAL :: refTime, elapsed
refTime = SECNDS(0.0)
elapsed = SECNDS(refTime)
PRINT *, "Elapsed seconds:", elapsed
END PROGRAM example_secnds
```

### Non-standard Intrinsics: SECOND
This intrinsic is an alias for `CPU_TIME`: supporting both a subroutine and a
function form.
Expand Down
2 changes: 2 additions & 0 deletions flang/include/flang/Optimizer/Builder/IntrinsicCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ struct IntrinsicLibrary {
llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genSecnds(mlir::Type resultType,
llvm::ArrayRef<fir::ExtendedValue> args);
fir::ExtendedValue genSecond(std::optional<mlir::Type>,
mlir::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genSelectedCharKind(mlir::Type,
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ void genRandomSeed(fir::FirOpBuilder &, mlir::Location, mlir::Value size,
void genRename(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value path1, mlir::Value path2, mlir::Value status);

mlir::Value genSecnds(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value refTime);

/// generate time runtime call
mlir::Value genTime(fir::FirOpBuilder &builder, mlir::Location loc);

Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,10 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"back", AnyLogical, Rank::elemental, Optionality::optional},
DefaultingKIND},
KINDInt},
{"secnds",
{{"refTime", TypePattern{RealType, KindCode::exactKind, 4},
Rank::scalar}},
TypePattern{RealType, KindCode::exactKind, 4}, Rank::scalar},
{"second", {}, DefaultReal, Rank::scalar},
{"selected_char_kind", {{"name", DefaultChar, Rank::scalar}}, DefaultInt,
Rank::scalar, IntrinsicClass::transformationalFunction},
Expand Down
20 changes: 20 additions & 0 deletions flang/lib/Optimizer/Builder/IntrinsicCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,10 @@ static constexpr IntrinsicHandler handlers[]{
{"back", asValue, handleDynamicOptional},
{"kind", asValue}}},
/*isElemental=*/true},
{"secnds",
&I::genSecnds,
{{{"refTime", asAddr}}},
/*isElemental=*/false},
{"second",
&I::genSecond,
{{{"time", asAddr}}},
Expand Down Expand Up @@ -7864,6 +7868,22 @@ IntrinsicLibrary::genScan(mlir::Type resultType,
return readAndAddCleanUp(resultMutableBox, resultType, "SCAN");
}

// SECNDS
fir::ExtendedValue
IntrinsicLibrary::genSecnds(mlir::Type resultType,
llvm::ArrayRef<fir::ExtendedValue> args) {
assert(args.size() == 1 && "SECNDS expects one argument");

mlir::Value refTime = fir::getBase(args[0]);

if (!refTime)
fir::emitFatalError(loc, "expected REFERENCE TIME parameter");

mlir::Value result = fir::runtime::genSecnds(builder, loc, refTime);

return builder.createConvert(loc, resultType, result);
}

// SECOND
fir::ExtendedValue
IntrinsicLibrary::genSecond(std::optional<mlir::Type> resultType,
Expand Down
17 changes: 17 additions & 0 deletions flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,23 @@ void fir::runtime::genRename(fir::FirOpBuilder &builder, mlir::Location loc,
fir::CallOp::create(builder, loc, runtimeFunc, args);
}

mlir::Value fir::runtime::genSecnds(fir::FirOpBuilder &builder,
mlir::Location loc, mlir::Value refTime) {
auto runtimeFunc =
fir::runtime::getRuntimeFunc<mkRTKey(Secnds)>(loc, builder);

mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType();

mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
mlir::Value sourceLine =
fir::factory::locationToLineNo(builder, loc, runtimeFuncTy.getInput(2));

llvm::SmallVector<mlir::Value> args = {refTime, sourceFile, sourceLine};
args = fir::runtime::createArguments(builder, loc, runtimeFuncTy, args);

return fir::CallOp::create(builder, loc, runtimeFunc, args).getResult(0);
}

/// generate runtime call to time intrinsic
mlir::Value fir::runtime::genTime(fir::FirOpBuilder &builder,
mlir::Location loc) {
Expand Down
23 changes: 23 additions & 0 deletions flang/test/Lower/Intrinsics/secnds.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
! RUN: bbc -emit-fir -hlfir=false %s -o - | FileCheck %s

! CHECK-LABEL: func.func @_QPuse_secnds(
! CHECK-SAME: %arg0: !fir.ref<f32>
function use_secnds(refTime) result(elapsed)
real :: refTime, elapsed
elapsed = secnds(refTime)
end function

! File/line operands (don’t match the actual path/number)
! CHECK: %[[STRADDR:.*]] = fir.address_of(
! CHECK: %[[LINE:.*]] = arith.constant {{.*}} : i32
! CHECK: %[[FNAME8:.*]] = fir.convert %[[STRADDR]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>

! Important: pass refTime by address and return a value f32
! CHECK: %[[CALL:.*]] = fir.call @{{.*}}Secnds(%arg0, %[[FNAME8]], %[[LINE]]) {{.*}} : (!fir.ref<f32>, !fir.ref<i8>, i32) -> f32

! Guard against illegal value ->ref conversion of result
! CHECK-NOT: fir.convert {{.*}} : (f32) -> !fir.ref<f32>

! Function returns an f32 value
! CHECK: return {{.*}} : f32