Skip to content

Commit 86bca29

Browse files
[flang] Register and lower SECNDS (stubbed implementation) (llvm#151878)
This patch registers and lowers the GNU extension intrinsic `SECNDS` in Flang. - Registration and lowering are wired through the intrinsic infrastructure. - genSecnds() currently emits a TODO fatal error, marking it as unimplemented. - Includes an XFAIL test to exercise the lowering path and reflect current status. Fixes llvm#58728 --- CC @eugeneepshteyn @klausler --------- Co-authored-by: Eugene Epshteyn <[email protected]>
1 parent e49946b commit 86bca29

File tree

7 files changed

+96
-0
lines changed

7 files changed

+96
-0
lines changed

flang/docs/Intrinsics.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,33 @@ program rename_proc
11231123
end program rename_proc
11241124
```
11251125

1126+
### Non-Standard Intrinsics: SECNDS
1127+
#### Description
1128+
`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.
1129+
1130+
#### Usage and Info
1131+
- **Standard:** GNU extension
1132+
- **Class:** function
1133+
- **Syntax:** result = `SECNDS(refTime)`
1134+
- **Arguments:**
1135+
1136+
| ARGUMENT | INTENT | TYPE | KIND | Description |
1137+
|-----------|--------|---------------|-------------------------|------------------------------------------|
1138+
| `refTime` | `IN` | `REAL, scalar`| REAL(KIND=4), required | Reference time in seconds since midnight |
1139+
1140+
- **Return Value:** REAL(KIND=4), scalar — seconds elapsed since `refTime`.
1141+
- **Purity:** Impure. SECNDS references the system clock and may not be invoked from a PURE procedure.
1142+
1143+
#### Example
1144+
```Fortran
1145+
PROGRAM example_secnds
1146+
REAL :: refTime, elapsed
1147+
refTime = SECNDS(0.0)
1148+
elapsed = SECNDS(refTime)
1149+
PRINT *, "Elapsed seconds:", elapsed
1150+
END PROGRAM example_secnds
1151+
```
1152+
11261153
### Non-standard Intrinsics: SECOND
11271154
This intrinsic is an alias for `CPU_TIME`: supporting both a subroutine and a
11281155
function form.

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,8 @@ struct IntrinsicLibrary {
407407
llvm::ArrayRef<fir::ExtendedValue>);
408408
mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
409409
fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
410+
fir::ExtendedValue genSecnds(mlir::Type resultType,
411+
llvm::ArrayRef<fir::ExtendedValue> args);
410412
fir::ExtendedValue genSecond(std::optional<mlir::Type>,
411413
mlir::ArrayRef<fir::ExtendedValue>);
412414
fir::ExtendedValue genSelectedCharKind(mlir::Type,

flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ void genRandomSeed(fir::FirOpBuilder &, mlir::Location, mlir::Value size,
7070
void genRename(fir::FirOpBuilder &builder, mlir::Location loc,
7171
mlir::Value path1, mlir::Value path2, mlir::Value status);
7272

73+
mlir::Value genSecnds(fir::FirOpBuilder &builder, mlir::Location loc,
74+
mlir::Value refTime);
75+
7376
/// generate time runtime call
7477
mlir::Value genTime(fir::FirOpBuilder &builder, mlir::Location loc);
7578

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,10 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
921921
{"back", AnyLogical, Rank::elemental, Optionality::optional},
922922
DefaultingKIND},
923923
KINDInt},
924+
{"secnds",
925+
{{"refTime", TypePattern{RealType, KindCode::exactKind, 4},
926+
Rank::scalar}},
927+
TypePattern{RealType, KindCode::exactKind, 4}, Rank::scalar},
924928
{"second", {}, DefaultReal, Rank::scalar},
925929
{"selected_char_kind", {{"name", DefaultChar, Rank::scalar}}, DefaultInt,
926930
Rank::scalar, IntrinsicClass::transformationalFunction},

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,10 @@ static constexpr IntrinsicHandler handlers[]{
869869
{"back", asValue, handleDynamicOptional},
870870
{"kind", asValue}}},
871871
/*isElemental=*/true},
872+
{"secnds",
873+
&I::genSecnds,
874+
{{{"refTime", asAddr}}},
875+
/*isElemental=*/false},
872876
{"second",
873877
&I::genSecond,
874878
{{{"time", asAddr}}},
@@ -7864,6 +7868,22 @@ IntrinsicLibrary::genScan(mlir::Type resultType,
78647868
return readAndAddCleanUp(resultMutableBox, resultType, "SCAN");
78657869
}
78667870

7871+
// SECNDS
7872+
fir::ExtendedValue
7873+
IntrinsicLibrary::genSecnds(mlir::Type resultType,
7874+
llvm::ArrayRef<fir::ExtendedValue> args) {
7875+
assert(args.size() == 1 && "SECNDS expects one argument");
7876+
7877+
mlir::Value refTime = fir::getBase(args[0]);
7878+
7879+
if (!refTime)
7880+
fir::emitFatalError(loc, "expected REFERENCE TIME parameter");
7881+
7882+
mlir::Value result = fir::runtime::genSecnds(builder, loc, refTime);
7883+
7884+
return builder.createConvert(loc, resultType, result);
7885+
}
7886+
78677887
// SECOND
78687888
fir::ExtendedValue
78697889
IntrinsicLibrary::genSecond(std::optional<mlir::Type> resultType,

flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,23 @@ void fir::runtime::genRename(fir::FirOpBuilder &builder, mlir::Location loc,
276276
fir::CallOp::create(builder, loc, runtimeFunc, args);
277277
}
278278

279+
mlir::Value fir::runtime::genSecnds(fir::FirOpBuilder &builder,
280+
mlir::Location loc, mlir::Value refTime) {
281+
auto runtimeFunc =
282+
fir::runtime::getRuntimeFunc<mkRTKey(Secnds)>(loc, builder);
283+
284+
mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType();
285+
286+
mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
287+
mlir::Value sourceLine =
288+
fir::factory::locationToLineNo(builder, loc, runtimeFuncTy.getInput(2));
289+
290+
llvm::SmallVector<mlir::Value> args = {refTime, sourceFile, sourceLine};
291+
args = fir::runtime::createArguments(builder, loc, runtimeFuncTy, args);
292+
293+
return fir::CallOp::create(builder, loc, runtimeFunc, args).getResult(0);
294+
}
295+
279296
/// generate runtime call to time intrinsic
280297
mlir::Value fir::runtime::genTime(fir::FirOpBuilder &builder,
281298
mlir::Location loc) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
! RUN: bbc -emit-fir -hlfir=false %s -o - | FileCheck %s
2+
3+
! CHECK-LABEL: func.func @_QPuse_secnds(
4+
! CHECK-SAME: %arg0: !fir.ref<f32>
5+
function use_secnds(refTime) result(elapsed)
6+
real :: refTime, elapsed
7+
elapsed = secnds(refTime)
8+
end function
9+
10+
! File/line operands (don’t match the actual path/number)
11+
! CHECK: %[[STRADDR:.*]] = fir.address_of(
12+
! CHECK: %[[LINE:.*]] = arith.constant {{.*}} : i32
13+
! CHECK: %[[FNAME8:.*]] = fir.convert %[[STRADDR]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
14+
15+
! Important: pass refTime by address and return a value f32
16+
! CHECK: %[[CALL:.*]] = fir.call @{{.*}}Secnds(%arg0, %[[FNAME8]], %[[LINE]]) {{.*}} : (!fir.ref<f32>, !fir.ref<i8>, i32) -> f32
17+
18+
! Guard against illegal value ->ref conversion of result
19+
! CHECK-NOT: fir.convert {{.*}} : (f32) -> !fir.ref<f32>
20+
21+
! Function returns an f32 value
22+
! CHECK: return {{.*}} : f32
23+

0 commit comments

Comments
 (0)