Skip to content

Commit 60ec686

Browse files
authored
[flang] Implement SECOND intrinsic (#98881)
The SECOND intrinsic is a gnu extension providing an alias for CPU_TIME: https://gcc.gnu.org/onlinedocs/gfortran/SECOND.html This cannot be implemented as a straightforward alias because there is both a function and a subroutine form.
1 parent fb2ab1c commit 60ec686

File tree

5 files changed

+81
-1
lines changed

5 files changed

+81
-1
lines changed

flang/docs/Intrinsics.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,3 +1047,16 @@ program rename_proc
10471047
call rename('dst', 'src')
10481048
end program rename_proc
10491049
```
1050+
1051+
### Non-standard Intrinsics: SECOND
1052+
This intrinsic is an alias for `CPU_TIME`: supporting both a subroutine and a
1053+
function form.
1054+
1055+
#### Usage and Info
1056+
1057+
- **Standard:** GNU extension
1058+
- **Class:** Subroutine, function
1059+
- **Syntax:** `CALL SECOND(TIME)` or `TIME = SECOND()`
1060+
- **Arguments:** `TIME` - a REAL value into which the elapsed CPU time in
1061+
seconds is written
1062+
- **RETURN value:** same as TIME argument

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ struct IntrinsicLibrary {
357357
llvm::ArrayRef<fir::ExtendedValue>);
358358
mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
359359
fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
360+
fir::ExtendedValue genSecond(std::optional<mlir::Type>,
361+
mlir::ArrayRef<fir::ExtendedValue>);
360362
fir::ExtendedValue genSelectedCharKind(mlir::Type,
361363
llvm::ArrayRef<fir::ExtendedValue>);
362364
mlir::Value genSelectedIntKind(mlir::Type, llvm::ArrayRef<mlir::Value>);

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
822822
{"back", AnyLogical, Rank::elemental, Optionality::optional},
823823
DefaultingKIND},
824824
KINDInt},
825+
{"second", {}, DefaultReal, Rank::scalar},
825826
{"selected_char_kind", {{"name", DefaultChar, Rank::scalar}}, DefaultInt,
826827
Rank::scalar, IntrinsicClass::transformationalFunction},
827828
{"selected_int_kind", {{"r", AnyInt, Rank::scalar}}, DefaultInt,
@@ -1474,6 +1475,8 @@ static const IntrinsicInterface intrinsicSubroutine[]{
14741475
{"status", DefaultInt, Rank::scalar, Optionality::optional,
14751476
common::Intent::Out}},
14761477
{}, Rank::scalar, IntrinsicClass::impureSubroutine},
1478+
{"second", {{"time", DefaultReal, Rank::scalar}}, {}, Rank::scalar,
1479+
IntrinsicClass::impureSubroutine},
14771480
{"system",
14781481
{{"command", DefaultChar, Rank::scalar},
14791482
{"exitstat", DefaultInt, Rank::scalar, Optionality::optional,
@@ -2623,7 +2626,7 @@ bool IntrinsicProcTable::Implementation::IsDualIntrinsic(
26232626
// Collection for some intrinsics with function and subroutine form,
26242627
// in order to pass the semantic check.
26252628
static const std::string dualIntrinsic[]{
2626-
{"etime"s}, {"getcwd"s}, {"rename"s}};
2629+
{"etime"s}, {"getcwd"s}, {"rename"s}, {"second"s}};
26272630

26282631
return std::find_if(std::begin(dualIntrinsic), std::end(dualIntrinsic),
26292632
[&name](const std::string &dualName) {

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,10 @@ static constexpr IntrinsicHandler handlers[]{
583583
{"back", asValue, handleDynamicOptional},
584584
{"kind", asValue}}},
585585
/*isElemental=*/true},
586+
{"second",
587+
&I::genSecond,
588+
{{{"time", asAddr}}},
589+
/*isElemental=*/false},
586590
{"selected_char_kind",
587591
&I::genSelectedCharKind,
588592
{{{"name", asAddr}}},
@@ -6140,6 +6144,27 @@ IntrinsicLibrary::genScan(mlir::Type resultType,
61406144
return readAndAddCleanUp(resultMutableBox, resultType, "SCAN");
61416145
}
61426146

6147+
// SECOND
6148+
fir::ExtendedValue
6149+
IntrinsicLibrary::genSecond(std::optional<mlir::Type> resultType,
6150+
mlir::ArrayRef<fir::ExtendedValue> args) {
6151+
assert(args.size() == 1 && !resultType || args.empty() && resultType);
6152+
6153+
fir::ExtendedValue result;
6154+
6155+
if (resultType)
6156+
result = builder.createTemporary(loc, *resultType);
6157+
else
6158+
result = args[0];
6159+
6160+
llvm::SmallVector<fir::ExtendedValue, 1> subroutineArgs(1, result);
6161+
genCpuTime(subroutineArgs);
6162+
6163+
if (resultType)
6164+
return result;
6165+
return {};
6166+
}
6167+
61436168
// SELECTED_CHAR_KIND
61446169
fir::ExtendedValue
61456170
IntrinsicLibrary::genSelectedCharKind(mlir::Type resultType,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
!RUN: bbc -emit-hlfir %s -o - | FileCheck %s
2+
!RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
3+
4+
subroutine test_subroutine(time)
5+
real :: time
6+
call second(time)
7+
end subroutine
8+
! CHECK-LABEL: func.func @_QPtest_subroutine(
9+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "time"}) {
10+
! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
11+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFtest_subroutineEtime"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
12+
! CHECK: %[[VAL_3:.*]] = fir.call @_FortranACpuTime() fastmath<contract> : () -> f64
13+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (f64) -> f32
14+
! CHECK: fir.store %[[VAL_4]] to %[[VAL_2]]#1 : !fir.ref<f32>
15+
! CHECK: return
16+
! CHECK: }
17+
18+
19+
subroutine test_function(time)
20+
real :: time
21+
time = second()
22+
end subroutine
23+
! CHECK-LABEL: func.func @_QPtest_function(
24+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "time"}) {
25+
! CHECK: %[[VAL_1:.*]] = fir.alloca f32
26+
! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
27+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_2]] {uniq_name = "_QFtest_functionEtime"} : (!fir.ref<f32>, !fir.dscope) -> (!fir.ref<f32>, !fir.ref<f32>)
28+
! CHECK: %[[VAL_4:.*]] = fir.call @_FortranACpuTime() fastmath<contract> : () -> f64
29+
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (f64) -> f32
30+
! CHECK: fir.store %[[VAL_5]] to %[[VAL_1]] : !fir.ref<f32>
31+
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = ".tmp.intrinsic_result"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
32+
! CHECK: %[[VAL_7:.*]] = arith.constant false
33+
! CHECK: %[[VAL_8:.*]] = hlfir.as_expr %[[VAL_6]]#0 move %[[VAL_7]] : (!fir.ref<f32>, i1) -> !hlfir.expr<f32>
34+
! CHECK: hlfir.assign %[[VAL_8]] to %[[VAL_3]]#0 : !hlfir.expr<f32>, !fir.ref<f32>
35+
! CHECK: hlfir.destroy %[[VAL_8]] : !hlfir.expr<f32>
36+
! CHECK: return
37+
! CHECK: }

0 commit comments

Comments
 (0)