Skip to content

Commit c787475

Browse files
committed
[flang] Register and lower SECNDS intrinsic (stubbed implementation)
- Updated SECNDS handler to pass `refTime` asAddr instead of asValue, matching the backend runtime contract (`float*`). - Addressed review feedback in the lowering hook: * Built the argument list using fir::runtime::createArguments * Replaced previous call emission with fir::CallOp::create(...) - Updated the regression test for SECNDS lowering to check argument passing, call signature, and return type. - Added documentation for SECNDS to Intrinsics.md, including description, usage, and example.
1 parent dae2e99 commit c787475

File tree

6 files changed

+87
-22
lines changed

6 files changed

+87
-22
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/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: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -922,10 +922,9 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
922922
DefaultingKIND},
923923
KINDInt},
924924
{"secnds",
925-
{{"x", TypePattern{RealType, KindCode::exactKind, 4}, Rank::scalar,
926-
Optionality::required, common::Intent::In}},
927-
TypePattern{RealType, KindCode::exactKind, 4}, Rank::scalar,
928-
IntrinsicClass::impureSubroutine},
925+
{{"refTime", TypePattern{RealType, KindCode::exactKind, 4},
926+
Rank::scalar}},
927+
TypePattern{RealType, KindCode::exactKind, 4}, Rank::scalar},
929928
{"second", {}, DefaultReal, Rank::scalar},
930929
{"selected_char_kind", {{"name", DefaultChar, Rank::scalar}}, DefaultInt,
931930
Rank::scalar, IntrinsicClass::transformationalFunction},
@@ -1893,7 +1892,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
18931892
// arguments in a procedure reference.
18941893
std::size_t dummyArgPatterns{0};
18951894
for (; dummyArgPatterns < maxArguments && dummy[dummyArgPatterns].keyword;
1896-
++dummyArgPatterns) {
1895+
++dummyArgPatterns) {
18971896
}
18981897
// MAX and MIN (and others that map to them) allow their last argument to
18991898
// be repeated indefinitely. The actualForDummy vector is sized
@@ -2697,7 +2696,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
26972696
// Rearrange the actual arguments into dummy argument order.
26982697
ActualArguments rearranged(dummies);
26992698
for (std::size_t j{0}; j < dummies; ++j) {
2700-
if (ActualArgument *arg{actualForDummy[j]}) {
2699+
if (ActualArgument * arg{actualForDummy[j]}) {
27012700
rearranged[j] = std::move(*arg);
27022701
}
27032702
}
@@ -3128,7 +3127,7 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
31283127
}
31293128
} else if (!IsInteroperableIntrinsicType(
31303129
*type, &context.languageFeatures())
3131-
.value_or(true)) {
3130+
.value_or(true)) {
31323131
if (type->category() == TypeCategory::Character &&
31333132
type->kind() == 1) {
31343133
if (context.languageFeatures().ShouldWarn(
@@ -3634,7 +3633,7 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
36343633
parser::Messages specificBuffer;
36353634
auto specificRange{specificFuncs_.equal_range(call.name)};
36363635
for (auto specIter{specificRange.first}; specIter != specificRange.second;
3637-
++specIter) {
3636+
++specIter) {
36383637
// We only need to check the cases with distinct generic names.
36393638
if (const char *genericName{specIter->second->generic}) {
36403639
if (auto specificCall{
@@ -3656,13 +3655,13 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
36563655
if (context.languageFeatures().IsEnabled(common::LanguageFeature::
36573656
UseGenericIntrinsicWhenSpecificDoesntMatch)) {
36583657
for (auto specIter{specificRange.first}; specIter != specificRange.second;
3659-
++specIter) {
3658+
++specIter) {
36603659
// We only need to check the cases with distinct generic names.
36613660
if (const char *genericName{specIter->second->generic}) {
36623661
if (specIter->second->useGenericAndForceResultType) {
36633662
auto genericRange{genericFuncs_.equal_range(genericName)};
36643663
for (auto genIter{genericRange.first}; genIter != genericRange.second;
3665-
++genIter) {
3664+
++genIter) {
36663665
if (auto specificCall{
36673666
matchOrBufferMessages(*genIter->second, specificBuffer)}) {
36683667
// Force the call result type to the specific intrinsic result

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,7 @@ static constexpr IntrinsicHandler handlers[]{
866866
/*isElemental=*/true},
867867
{"secnds",
868868
&I::genSecnds,
869-
{{{"x", asValue}}},
869+
{{{"refTime", asAddr}}},
870870
/*isElemental=*/false},
871871
{"second",
872872
&I::genSecond,
@@ -7818,11 +7818,19 @@ IntrinsicLibrary::genScan(mlir::Type resultType,
78187818
}
78197819

78207820
// SECNDS
7821-
// Lowering is registered, runtime not yet implemented
78227821
fir::ExtendedValue
78237822
IntrinsicLibrary::genSecnds(mlir::Type resultType,
78247823
llvm::ArrayRef<fir::ExtendedValue> args) {
7825-
TODO(loc, "not yet implemented: SECNDS");
7824+
assert(args.size() == 1 && "SECNDS expects one argument");
7825+
7826+
mlir::Value refTime = fir::getBase(args[0]);
7827+
7828+
if (!refTime)
7829+
fir::emitFatalError(loc, "expected REFERENCE TIME parameter");
7830+
7831+
mlir::Value result = fir::runtime::genSecnds(builder, loc, refTime);
7832+
7833+
return builder.createConvert(loc, resultType, result);
78267834
}
78277835

78287836
// SECOND

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: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1-
!---------------------------------------------------------------------
2-
! RUN: %flang_fc1 -emit-fir %s -o - 2>&1 | FileCheck %s
3-
! XFAIL: *
4-
!---------------------------------------------------------------------
1+
! RUN: bbc -emit-fir -hlfir=false %s -o - | FileCheck %s
52

6-
program test_secnds
7-
real :: x
8-
x = secnds(1.0)
9-
end program
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
109

11-
! CHECK: not yet implemented: SECNDS
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
1223

0 commit comments

Comments
 (0)