Skip to content

Commit 513a91a

Browse files
authored
[flang/flang-rt] Implement PERROR intrinsic form GNU Extension (#132406)
Add the implementation of the `PERROR(STRING) ` intrinsic from the GNU Extension to prints on the stderr a newline-terminated error message corresponding to the last system error prefixed by `STRING`. (https://gcc.gnu.org/onlinedocs/gfortran/PERROR.html)
1 parent bcf0f8d commit 513a91a

File tree

9 files changed

+105
-0
lines changed

9 files changed

+105
-0
lines changed

flang-rt/lib/runtime/extensions.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "flang/Runtime/entry-names.h"
1818
#include "flang/Runtime/io-api.h"
1919
#include <chrono>
20+
#include <cstdio>
2021
#include <cstring>
2122
#include <ctime>
2223
#include <signal.h>
@@ -268,5 +269,8 @@ void FORTRAN_PROCEDURE_NAME(qsort)(int *array, int *len, int *isize,
268269
qsort(array, *len, *isize, compar);
269270
}
270271

272+
// PERROR(STRING)
273+
void RTNAME(Perror)(const char *str) { perror(str); }
274+
271275
} // namespace Fortran::runtime
272276
} // extern "C"

flang/docs/Intrinsics.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,3 +1175,15 @@ by `ISIZE`.
11751175
- **Standard:** lib3f (section 3f of old man pages).
11761176
- **Class:** subroutine
11771177
- **Syntax:** `CALL QSORT(ARRAY, LEN, ISIZE, COMPAR)`
1178+
1179+
### Non-Standard Intrinsics: PERROR
1180+
1181+
#### Description
1182+
`PERROR(STRING)` prints (on the C stderr stream) a newline-terminated error message corresponding to the last system error.
1183+
This is prefixed by `STRING`, a colon and a space.
1184+
1185+
#### Usage and Info
1186+
1187+
- **Standard:** GNU extension
1188+
- **Class:** subroutine
1189+
- **Syntax:** `CALL PERROR(STRING)`

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ struct IntrinsicLibrary {
373373
fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
374374
fir::ExtendedValue genPack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
375375
fir::ExtendedValue genParity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
376+
void genPerror(llvm::ArrayRef<fir::ExtendedValue>);
376377
mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
377378
mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
378379
fir::ExtendedValue genPresent(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,10 @@ mlir::Value genGetCwd(fir::FirOpBuilder &builder, mlir::Location loc,
6363
mlir::Value genHostnm(fir::FirOpBuilder &builder, mlir::Location loc,
6464
mlir::Value res);
6565

66+
/// Generate a call to the Perror runtime function which implements
67+
/// the PERROR GNU intrinsic.
68+
void genPerror(fir::FirOpBuilder &builder, mlir::Location loc,
69+
mlir::Value string);
70+
6671
} // namespace fir::runtime
6772
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COMMAND_H

flang/include/flang/Runtime/extensions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,8 @@ int RTNAME(Chdir)(const char *name);
7878
// GNU extension function IERRNO()
7979
int FORTRAN_PROCEDURE_NAME(ierrno)();
8080

81+
// GNU extension subroutine PERROR(STRING)
82+
void RTNAME(Perror)(const char *str);
83+
8184
} // extern "C"
8285
#endif // FORTRAN_RUNTIME_EXTENSIONS_H_

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,8 @@ static const IntrinsicInterface intrinsicSubroutine[]{
15731573
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional,
15741574
common::Intent::InOut}},
15751575
{}, Rank::elemental, IntrinsicClass::pureSubroutine},
1576+
{"perror", {{"string", DefaultChar, Rank::scalar}}, {}, Rank::elemental,
1577+
IntrinsicClass::impureSubroutine},
15761578
{"mvbits",
15771579
{{"from", SameIntOrUnsigned}, {"frompos", AnyInt}, {"len", AnyInt},
15781580
{"to", SameIntOrUnsigned, Rank::elemental, Optionality::required,

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,10 @@ static constexpr IntrinsicHandler handlers[]{
753753
&I::genParity,
754754
{{{"mask", asBox}, {"dim", asValue}}},
755755
/*isElemental=*/false},
756+
{"perror",
757+
&I::genPerror,
758+
{{{"string", asBox}}},
759+
/*isElemental*/ false},
756760
{"popcnt", &I::genPopcnt},
757761
{"poppar", &I::genPoppar},
758762
{"present",
@@ -7158,6 +7162,17 @@ IntrinsicLibrary::genParity(mlir::Type resultType,
71587162
return readAndAddCleanUp(resultMutableBox, resultType, "PARITY");
71597163
}
71607164

7165+
// PERROR
7166+
void IntrinsicLibrary::genPerror(llvm::ArrayRef<fir::ExtendedValue> args) {
7167+
assert(args.size() == 1);
7168+
7169+
fir::ExtendedValue str = args[0];
7170+
const auto *box = str.getBoxOf<fir::BoxValue>();
7171+
mlir::Value addr =
7172+
builder.create<fir::BoxAddrOp>(loc, box->getMemTy(), fir::getBase(*box));
7173+
fir::runtime::genPerror(builder, loc, addr);
7174+
}
7175+
71617176
// POPCNT
71627177
mlir::Value IntrinsicLibrary::genPopcnt(mlir::Type resultType,
71637178
llvm::ArrayRef<mlir::Value> args) {

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "flang/Optimizer/Builder/FIRBuilder.h"
1111
#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
1212
#include "flang/Runtime/command.h"
13+
#include "flang/Runtime/extensions.h"
1314

1415
using namespace Fortran::runtime;
1516

@@ -114,3 +115,13 @@ mlir::Value fir::runtime::genHostnm(fir::FirOpBuilder &builder,
114115
builder, loc, runtimeFuncTy, res, sourceFile, sourceLine);
115116
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
116117
}
118+
119+
void fir::runtime::genPerror(fir::FirOpBuilder &builder, mlir::Location loc,
120+
mlir::Value string) {
121+
auto runtimeFunc =
122+
fir::runtime::getRuntimeFunc<mkRTKey(Perror)>(loc, builder);
123+
mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType();
124+
llvm::SmallVector<mlir::Value> args =
125+
fir::runtime::createArguments(builder, loc, runtimeFuncTy, string);
126+
builder.create<fir::CallOp>(loc, runtimeFunc, args);
127+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
! RUN: bbc -emit-hlfir %s -o - | FileCheck --check-prefixes=CHECK %s
2+
! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck --check-prefixes=CHECK %s
3+
4+
! CHECK-LABEL: func @_QPtest_perror(
5+
subroutine test_perror()
6+
character(len=10) :: string
7+
character(len=1) :: one
8+
! CHECK: %[[C1:.*]] = arith.constant 1 : index
9+
! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.char<1> {bindc_name = "one", uniq_name = "_QFtest_perrorEone"}
10+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[C1]] {uniq_name = "_QFtest_perrorEone"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
11+
! CHECK: %[[C10:.*]] = arith.constant 10 : index
12+
! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.char<1,10> {bindc_name = "string", uniq_name = "_QFtest_perrorEstring"}
13+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[C10]] {uniq_name = "_QFtest_perrorEstring"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>)
14+
15+
call perror(string)
16+
! CHECK: %[[VAL_4:.*]] = fir.embox %[[VAL_3]]#0 : (!fir.ref<!fir.char<1,10>>) -> !fir.box<!fir.char<1,10>>
17+
! CHECK: %[[VAL_5:.*]] = fir.box_addr %[[VAL_4]] : (!fir.box<!fir.char<1,10>>) -> !fir.ref<!fir.char<1,10>>
18+
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<i8>
19+
! CHECK: fir.call @_FortranAPerror(%[[VAL_6]]) fastmath<contract> : (!fir.ref<i8>) -> ()
20+
21+
call perror("prefix")
22+
! CHECK: %[[VAL_7:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,6>>
23+
! CHECK: %[[C6:.*]] = arith.constant 6 : index
24+
! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[C6]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = {{.*}}} : (!fir.ref<!fir.char<1,6>>, index) -> (!fir.ref<!fir.char<1,6>>, !fir.ref<!fir.char<1,6>>)
25+
! CHECK: %[[VAL_9:.*]] = fir.embox %[[VAL_8]]#0 : (!fir.ref<!fir.char<1,6>>) -> !fir.box<!fir.char<1,6>>
26+
! CHECK: %[[VAL_10:.*]] = fir.box_addr %[[VAL_9]] : (!fir.box<!fir.char<1,6>>) -> !fir.ref<!fir.char<1,6>>
27+
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<!fir.char<1,6>>) -> !fir.ref<i8>
28+
! CHECK: fir.call @_FortranAPerror(%[[VAL_11]]) fastmath<contract> : (!fir.ref<i8>) -> ()
29+
30+
call perror(one)
31+
! CHECK: %[[VAL_12:.*]] = fir.embox %[[VAL_1]]#0 : (!fir.ref<!fir.char<1>>) -> !fir.box<!fir.char<1>>
32+
! CHECK: %[[VAL_13:.*]] = fir.box_addr %[[VAL_12]] : (!fir.box<!fir.char<1>>) -> !fir.ref<!fir.char<1>>
33+
! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<!fir.char<1>>) -> !fir.ref<i8>
34+
! CHECK: fir.call @_FortranAPerror(%[[VAL_14]]) fastmath<contract> : (!fir.ref<i8>) -> ()
35+
end subroutine test_perror
36+
37+
! CHECK-LABEL: func @_QPtest_perror_unknown_length(
38+
! CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1> {fir.bindc_name = "str"}
39+
subroutine test_perror_unknown_length(str)
40+
implicit none
41+
character(len=*), intent(in) :: str
42+
43+
call perror(str)
44+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
45+
! CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
46+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]]#0 typeparams %[[VAL_1]]#1 dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest_perror_unknown_lengthEstr"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
47+
! CHECK: %[[VAL_3:.*]] = fir.embox %[[VAL_2]]#1 typeparams %[[VAL_1]]#1 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.box<!fir.char<1,?>>
48+
! CHECK: %[[VAL_4:.*]] = fir.box_addr %[[VAL_3]] : (!fir.box<!fir.char<1,?>>) -> !fir.ref<!fir.char<1,?>>
49+
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
50+
! CHECK: fir.call @_FortranAPerror(%[[VAL_5]]) fastmath<contract> : (!fir.ref<i8>) -> ()
51+
! CHECK: return
52+
end subroutine test_perror_unknown_length

0 commit comments

Comments
 (0)