Skip to content

Commit 005aa9c

Browse files
committed
[flang/flang-rt] Implement PERROR intrinsic form GNU Extension
1 parent 924c7ea commit 005aa9c

File tree

9 files changed

+98
-0
lines changed

9 files changed

+98
-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
@@ -1137,3 +1137,15 @@ by `ISIZE`.
11371137
- **Standard:** lib3f (section 3f of old man pages).
11381138
- **Class:** subroutine
11391139
- **Syntax:** `CALL QSORT(ARRAY, LEN, ISIZE, COMPAR)`
1140+
1141+
### Non-Standard Intrinsics: PERROR
1142+
1143+
#### Description
1144+
`PERROR(STRING)` prints (on the C stderr stream) a newline-terminated error message corresponding to the last system error.
1145+
This is prefixed by `STRING`, a colon and a space.
1146+
1147+
#### Usage and Info
1148+
1149+
- **Standard:** GNU extension
1150+
- **Class:** subroutine
1151+
- **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
@@ -371,6 +371,7 @@ struct IntrinsicLibrary {
371371
fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
372372
fir::ExtendedValue genPack(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
373373
fir::ExtendedValue genParity(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
374+
void genPerror(llvm::ArrayRef<fir::ExtendedValue>);
374375
mlir::Value genPopcnt(mlir::Type, llvm::ArrayRef<mlir::Value>);
375376
mlir::Value genPoppar(mlir::Type, llvm::ArrayRef<mlir::Value>);
376377
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
@@ -58,5 +58,10 @@ mlir::Value genGetEnvVariable(fir::FirOpBuilder &, mlir::Location,
5858
mlir::Value genGetCwd(fir::FirOpBuilder &builder, mlir::Location loc,
5959
mlir::Value c);
6060

61+
/// Generate a call to the Perror runtime function which implements
62+
/// the PERROR GNU intrinsic.
63+
void genPerror(fir::FirOpBuilder &builder, mlir::Location loc,
64+
mlir::Value string);
65+
6166
} // namespace fir::runtime
6267
#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
@@ -75,5 +75,8 @@ int RTNAME(Chdir)(const char *name);
7575
// GNU extension function IERRNO()
7676
int FORTRAN_PROCEDURE_NAME(ierrno)();
7777

78+
// GNU extension subroutine PERROR(STRING)
79+
void RTNAME(Perror)(const char *str);
80+
7881
} // extern "C"
7982
#endif // FORTRAN_RUNTIME_EXTENSIONS_H_

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,8 @@ static const IntrinsicInterface intrinsicSubroutine[]{
15551555
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional,
15561556
common::Intent::InOut}},
15571557
{}, Rank::elemental, IntrinsicClass::pureSubroutine},
1558+
{"perror", {{"string", DefaultChar, Rank::scalar}}, {}, Rank::elemental,
1559+
IntrinsicClass::impureSubroutine},
15581560
{"mvbits",
15591561
{{"from", SameIntOrUnsigned}, {"frompos", AnyInt}, {"len", AnyInt},
15601562
{"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
@@ -749,6 +749,10 @@ static constexpr IntrinsicHandler handlers[]{
749749
&I::genParity,
750750
{{{"mask", asBox}, {"dim", asValue}}},
751751
/*isElemental=*/false},
752+
{"perror",
753+
&I::genPerror,
754+
{{{"string", asBox}}},
755+
/*isElemental*/ false},
752756
{"popcnt", &I::genPopcnt},
753757
{"poppar", &I::genPoppar},
754758
{"present",
@@ -7085,6 +7089,17 @@ IntrinsicLibrary::genParity(mlir::Type resultType,
70857089
return readAndAddCleanUp(resultMutableBox, resultType, "PARITY");
70867090
}
70877091

7092+
// PERROR
7093+
void IntrinsicLibrary::genPerror(llvm::ArrayRef<fir::ExtendedValue> args) {
7094+
assert(args.size() == 1);
7095+
7096+
fir::ExtendedValue str = args[0];
7097+
const auto *box = str.getBoxOf<fir::BoxValue>();
7098+
mlir::Value addr =
7099+
builder.create<fir::BoxAddrOp>(loc, box->getMemTy(), fir::getBase(*box));
7100+
fir::runtime::genPerror(builder, loc, addr);
7101+
}
7102+
70887103
// POPCNT
70897104
mlir::Value IntrinsicLibrary::genPopcnt(mlir::Type resultType,
70907105
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

@@ -101,3 +102,13 @@ mlir::Value fir::runtime::genGetCwd(fir::FirOpBuilder &builder,
101102
builder, loc, runtimeFuncTy, cwd, sourceFile, sourceLine);
102103
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
103104
}
105+
106+
void fir::runtime::genPerror(fir::FirOpBuilder &builder, mlir::Location loc,
107+
mlir::Value string) {
108+
auto runtimeFunc =
109+
fir::runtime::getRuntimeFunc<mkRTKey(Perror)>(loc, builder);
110+
mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType();
111+
llvm::SmallVector<mlir::Value> args =
112+
fir::runtime::createArguments(builder, loc, runtimeFuncTy, string);
113+
builder.create<fir::CallOp>(loc, runtimeFunc, args);
114+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
! RUN: bbc -emit-fir %s -o - | FileCheck --check-prefixes=CHECK %s
2+
! RUN: %flang_fc1 -emit-fir %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: %[[C6:.*]] = arith.constant 6 : index
9+
! CHECK: %[[C10:.*]] = arith.constant 10 : index
10+
! CHECK: %[[C1:.*]] = arith.constant 1 : index
11+
! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.char<1> {bindc_name = "one", uniq_name = "_QFtest_perrorEone"}
12+
! CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] typeparams %[[C1]] {uniq_name = "_QFtest_perrorEone"} : (!fir.ref<!fir.char<1>>, index) -> !fir.ref<!fir.char<1>>
13+
! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.char<1,10> {bindc_name = "string", uniq_name = "_QFtest_perrorEstring"}
14+
! CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_2]] typeparams %[[C10]] {uniq_name = "_QFtest_perrorEstring"} : (!fir.ref<!fir.char<1,10>>, index) -> !fir.ref<!fir.char<1,10>>
15+
16+
call perror(string)
17+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.char<1,10>>) -> !fir.ref<i8>
18+
! CHECK: fir.call @_FortranAPerror(%[[VAL_4]]) fastmath<contract> : (!fir.ref<i8>) -> ()
19+
20+
call perror("prefix")
21+
! CHECK: %[[VAL_5:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1,6>>
22+
! CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_5]] typeparams %[[C6]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = {{.*}}} : (!fir.ref<!fir.char<1,6>>, index) -> !fir.ref<!fir.char<1,6>>
23+
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<!fir.char<1,6>>) -> !fir.ref<i8>
24+
! CHECK: fir.call @_FortranAPerror(%[[VAL_7]]) fastmath<contract> : (!fir.ref<i8>) -> ()
25+
26+
call perror(one)
27+
! CHECK: %[[VAL_8:.*]] = fir.convert %1 : (!fir.ref<!fir.char<1>>) -> !fir.ref<i8>
28+
! CHECK: fir.call @_FortranAPerror(%[[VAL_8]]) fastmath<contract> : (!fir.ref<i8>) -> ()
29+
end subroutine test_perror
30+
31+
! CHECK-LABEL: func @_QPtest_perror_unknown_length(
32+
! CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1> {fir.bindc_name = "str"}
33+
subroutine test_perror_unknown_length(str)
34+
implicit none
35+
character(len=*), intent(in) :: str
36+
37+
call perror(str)
38+
! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
39+
! CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
40+
! CHECK: %[[VAL_2:.*]] = fir.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.ref<!fir.char<1,?>>
41+
! CHECK: %[[VAL_3:.*]] = fir.emboxchar %[[VAL_2]], %[[VAL_1]]#1 : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
42+
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
43+
! CHECK: fir.call @_FortranAPerror(%[[VAL_4]]) fastmath<contract> : (!fir.ref<i8>) -> ()
44+
! CHECK: return
45+
end subroutine test_perror_unknown_length

0 commit comments

Comments
 (0)