Skip to content

Commit 2c8e260

Browse files
[flang] Add HOSTNM runtime and lowering intrinsics implementation (#131910)
Implement GNU extension intrinsic HOSTNM, both function and subroutine forms. Add HOSTNM documentation to `flang/docs/Intrinsics.md`. Add lowering and semantic unit tests. (This change is modeled after GETCWD implementation.)
1 parent 6ddc071 commit 2c8e260

File tree

13 files changed

+262
-7
lines changed

13 files changed

+262
-7
lines changed

flang-rt/lib/runtime/command.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,48 @@ std::int32_t RTNAME(GetCwd)(
263263
return status;
264264
}
265265

266+
std::int32_t RTNAME(Hostnm)(
267+
const Descriptor &res, const char *sourceFile, int line) {
268+
Terminator terminator{sourceFile, line};
269+
270+
RUNTIME_CHECK(terminator, IsValidCharDescriptor(&res));
271+
272+
char buf[256];
273+
std::int32_t status{0};
274+
275+
// Fill the output with spaces. Upon success, CopyCharsToDescriptor()
276+
// will overwrite part of the string with the result, so we'll end up
277+
// with a padded string. If we fail to obtain the host name, we return
278+
// the string of all spaces, which is the original gfortran behavior.
279+
FillWithSpaces(res);
280+
281+
#ifdef _WIN32
282+
283+
DWORD dwSize{sizeof(buf)};
284+
285+
// Note: Winsock has gethostname(), but use Win32 API GetComputerNameEx(),
286+
// in order to avoid adding dependency on Winsock.
287+
if (!GetComputerNameExA(ComputerNameDnsHostname, buf, &dwSize)) {
288+
status = GetLastError();
289+
}
290+
291+
#else
292+
293+
if (gethostname(buf, sizeof(buf)) < 0) {
294+
status = errno;
295+
}
296+
297+
#endif
298+
299+
if (status == 0) {
300+
std::int64_t strLen{StringLength(buf)};
301+
status = CopyCharsToDescriptor(res, buf, strLen);
302+
303+
// Note: if the result string is too short, then we'll return partial
304+
// host name with "too short" error status.
305+
}
306+
307+
return status;
308+
}
309+
266310
} // namespace Fortran::runtime

flang/docs/Intrinsics.md

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<!--===- docs/Intrinsics.md
2-
1+
<!--===- docs/Intrinsics.md
2+
33
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
See https://llvm.org/LICENSE.txt for license information.
55
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6-
6+
77
-->
88

99
# A categorization of standard (2018) and extended Fortran intrinsic procedures
@@ -703,7 +703,7 @@ CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, LOC
703703
MALLOC, FREE
704704
```
705705

706-
### Library subroutine
706+
### Library subroutine
707707
```
708708
CALL BACKTRACE()
709709
CALL FDATE(TIME)
@@ -961,7 +961,7 @@ program test_etime
961961
call ETIME(tarray, result)
962962
print *, result
963963
print *, tarray(1)
964-
print *, tarray(2)
964+
print *, tarray(2)
965965
do i=1,100000000 ! Just a delay
966966
j = i * i - i
967967
end do
@@ -1003,6 +1003,38 @@ PROGRAM example_getcwd
10031003
END PROGRAM
10041004
```
10051005

1006+
### Non-Standard Intrinsics: HOSTNM
1007+
1008+
#### Description
1009+
`HOSTNM(C, STATUS)` returns the host name of the system.
1010+
1011+
This intrinsic is provided in both subroutine and function forms; however, only one form can be used in any given program unit.
1012+
1013+
*C* and *STATUS* are `INTENT(OUT)` and provide the following:
1014+
1015+
| | |
1016+
|------------|---------------------------------------------------------------------------------------------------|
1017+
| `C` | The host name of the system. The type shall be `CHARACTER` and of default kind. |
1018+
| `STATUS` | (Optional) Status flag. Returns 0 on success, a system specific and nonzero error code otherwise. The type shall be `INTEGER` and of a kind greater or equal to 4. |
1019+
1020+
#### Usage and Info
1021+
1022+
- **Standard:** GNU extension
1023+
- **Class:** Subroutine, function
1024+
- **Syntax:** `CALL HOSTNM(C, STATUS)`, `STATUS = HOSTNM(C)`
1025+
1026+
#### Example
1027+
```Fortran
1028+
PROGRAM example_hostnm
1029+
CHARACTER(len=255) :: hnam
1030+
INTEGER :: status
1031+
CALL hostnm(hnam, status)
1032+
PRINT *, hnam
1033+
PRINT *, status
1034+
END PROGRAM
1035+
```
1036+
1037+
10061038
### Non-standard Intrinsics: RENAME
10071039
`RENAME(OLD, NEW[, STATUS])` renames/moves a file on the filesystem.
10081040

@@ -1088,7 +1120,7 @@ This intrinsic is provided in both subroutine and function forms; however, only
10881120
```Fortran
10891121
program chdir_func
10901122
character(len=) :: path
1091-
integer :: status
1123+
integer :: status
10921124
10931125
call chdir("/tmp")
10941126
status = chdir("..")

flang/include/flang/Common/windows-include.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#define WIN32_LEAN_AND_MEAN
1919
#define NOMINMAX
2020

21+
// Target Windows 2000 and above. This is needed for newer Windows API
22+
// functions, e.g. GetComputerNameExA()
23+
#define _WIN32_WINNT 0x0500
24+
2125
#include <windows.h>
2226

2327
#endif // _WIN32

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ struct IntrinsicLibrary {
277277
llvm::ArrayRef<mlir::Value> args);
278278
mlir::Value genGetUID(mlir::Type resultType,
279279
llvm::ArrayRef<mlir::Value> args);
280+
fir::ExtendedValue genHostnm(std::optional<mlir::Type> resultType,
281+
llvm::ArrayRef<fir::ExtendedValue> args);
280282
fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
281283
mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
282284
fir::ExtendedValue genIany(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 Hostnm runtime function which implements
62+
/// the HOSTNM intrinsic.
63+
mlir::Value genHostnm(fir::FirOpBuilder &builder, mlir::Location loc,
64+
mlir::Value res);
65+
6166
} // namespace fir::runtime
6267
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_COMMAND_H

flang/include/flang/Runtime/command.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ std::int32_t RTNAME(GetEnvVariable)(const Descriptor &name,
5959
// Calls getcwd()
6060
std::int32_t RTNAME(GetCwd)(
6161
const Descriptor &cwd, const char *sourceFile, int line);
62+
63+
// Calls hostnm()
64+
std::int32_t RTNAME(Hostnm)(
65+
const Descriptor &res, const char *sourceFile, int line);
6266
}
6367
} // namespace Fortran::runtime
6468

flang/include/flang/Runtime/extensions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ uid_t RTNAME(GetUID)();
5454
// GNU extension subroutine GETLOG(C).
5555
void FORTRAN_PROCEDURE_NAME(getlog)(char *name, std::int64_t length);
5656

57+
// GNU extension subroutine HOSTNM(C)
58+
void FORTRAN_PROCEDURE_NAME(hostnm)(char *name, std::int64_t length);
59+
5760
std::intptr_t RTNAME(Malloc)(std::size_t size);
5861

5962
// GNU extension function STATUS = SIGNAL(number, handler)

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,10 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
553553
{"getgid", {}, DefaultInt},
554554
{"getpid", {}, DefaultInt},
555555
{"getuid", {}, DefaultInt},
556+
{"hostnm",
557+
{{"c", DefaultChar, Rank::scalar, Optionality::required,
558+
common::Intent::Out}},
559+
TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}},
556560
{"huge",
557561
{{"x", SameIntUnsignedOrReal, Rank::anyOrAssumedRank,
558562
Optionality::required, common::Intent::In,
@@ -1545,6 +1549,12 @@ static const IntrinsicInterface intrinsicSubroutine[]{
15451549
{"status", TypePattern{IntType, KindCode::greaterOrEqualToKind, 4},
15461550
Rank::scalar, Optionality::optional, common::Intent::Out}},
15471551
{}, Rank::elemental, IntrinsicClass::impureSubroutine},
1552+
{"hostnm",
1553+
{{"c", DefaultChar, Rank::scalar, Optionality::required,
1554+
common::Intent::Out},
1555+
{"status", TypePattern{IntType, KindCode::greaterOrEqualToKind, 4},
1556+
Rank::scalar, Optionality::optional, common::Intent::Out}},
1557+
{}, Rank::elemental, IntrinsicClass::impureSubroutine},
15481558
{"move_alloc",
15491559
{{"from", SameType, Rank::known, Optionality::required,
15501560
common::Intent::InOut},
@@ -2765,7 +2775,7 @@ bool IntrinsicProcTable::Implementation::IsDualIntrinsic(
27652775
// Collection for some intrinsics with function and subroutine form,
27662776
// in order to pass the semantic check.
27672777
static const std::string dualIntrinsic[]{{"chdir"s}, {"etime"s}, {"getcwd"s},
2768-
{"rename"s}, {"second"s}, {"system"s}};
2778+
{"hostnm"s}, {"rename"s}, {"second"s}, {"system"s}};
27692779

27702780
return llvm::is_contained(dualIntrinsic, name);
27712781
}

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,10 @@ static constexpr IntrinsicHandler handlers[]{
480480
{"getgid", &I::genGetGID},
481481
{"getpid", &I::genGetPID},
482482
{"getuid", &I::genGetUID},
483+
{"hostnm",
484+
&I::genHostnm,
485+
{{{"c", asBox}, {"status", asAddr, handleDynamicOptional}}},
486+
/*isElemental=*/false},
483487
{"iachar", &I::genIchar},
484488
{"iall",
485489
&I::genIall,
@@ -4317,6 +4321,37 @@ void IntrinsicLibrary::genGetEnvironmentVariable(
43174321
}
43184322
}
43194323

4324+
// HOSTNM
4325+
fir::ExtendedValue
4326+
IntrinsicLibrary::genHostnm(std::optional<mlir::Type> resultType,
4327+
llvm::ArrayRef<fir::ExtendedValue> args) {
4328+
assert((args.size() == 1 && resultType.has_value()) ||
4329+
(args.size() >= 1 && !resultType.has_value()));
4330+
4331+
mlir::Value res = fir::getBase(args[0]);
4332+
mlir::Value statusValue = fir::runtime::genHostnm(builder, loc, res);
4333+
4334+
if (resultType.has_value()) {
4335+
// Function form, return status.
4336+
return builder.createConvert(loc, *resultType, statusValue);
4337+
}
4338+
4339+
// Subroutine form, store status and return none.
4340+
const fir::ExtendedValue &status = args[1];
4341+
if (!isStaticallyAbsent(status)) {
4342+
mlir::Value statusAddr = fir::getBase(status);
4343+
mlir::Value statusIsPresentAtRuntime =
4344+
builder.genIsNotNullAddr(loc, statusAddr);
4345+
builder.genIfThen(loc, statusIsPresentAtRuntime)
4346+
.genThen([&]() {
4347+
builder.createStoreWithConvert(loc, statusValue, statusAddr);
4348+
})
4349+
.end();
4350+
}
4351+
4352+
return {};
4353+
}
4354+
43204355
/// Process calls to Maxval, Minval, Product, Sum intrinsic functions that
43214356
/// take a DIM argument.
43224357
template <typename FD>

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,16 @@ mlir::Value fir::runtime::genGetCwd(fir::FirOpBuilder &builder,
101101
builder, loc, runtimeFuncTy, cwd, sourceFile, sourceLine);
102102
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
103103
}
104+
105+
mlir::Value fir::runtime::genHostnm(fir::FirOpBuilder &builder,
106+
mlir::Location loc, mlir::Value res) {
107+
mlir::func::FuncOp func =
108+
fir::runtime::getRuntimeFunc<mkRTKey(Hostnm)>(loc, builder);
109+
auto runtimeFuncTy = func.getFunctionType();
110+
mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
111+
mlir::Value sourceLine =
112+
fir::factory::locationToLineNo(builder, loc, runtimeFuncTy.getInput(2));
113+
llvm::SmallVector<mlir::Value> args = fir::runtime::createArguments(
114+
builder, loc, runtimeFuncTy, res, sourceFile, sourceLine);
115+
return builder.create<fir::CallOp>(loc, func, args).getResult(0);
116+
}

0 commit comments

Comments
 (0)