Skip to content

Commit 856c38d

Browse files
DavidTrubyyiwu0b11
andauthored
[flang] Implement GETUID and GETGID intrinsics (llvm#110679)
GETUID and GETGID are non-standard intrinsics supported by a number of other Fortran compilers. On supported platforms these intrinsics simply call the POSIX getuid() and getgid() functions and return the result. The only platform we support that does not have these is Windows. Windows does not have the same concept of UIDs and GIDs, so on Windows we issue a warning indicating this and return 1 from both functions. Co-authored-by: Yi Wu <yi.wu2@arm.com>
1 parent 391e64c commit 856c38d

File tree

17 files changed

+139
-2
lines changed

17 files changed

+139
-2
lines changed

flang/docs/Intrinsics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ This phase currently supports all the intrinsic procedures listed above but the
765765
| Coarray intrinsic functions | COSHAPE |
766766
| Object characteristic inquiry functions | ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS, PRESENT, RANK, SAME_TYPE, STORAGE_SIZE |
767767
| Type inquiry intrinsic functions | BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT, NEW_LINE, PRECISION, RADIX, RANGE, TINY|
768-
| Non-standard intrinsic functions | AND, OR, XOR, SHIFT, ZEXT, IZEXT, COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM, NUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF, MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR, IARG, IARGC, NARGS, GETPID, NUMARG, BADDRESS, IADDR, CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC, FREE |
768+
| Non-standard intrinsic functions | AND, OR, XOR, SHIFT, ZEXT, IZEXT, COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM, NUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF, MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR, IARG, IARGC, NARGS, GETPID, NUMARG, BADDRESS, IADDR, CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC, FREE, GETUID, GETGID |
769769
| Intrinsic subroutines |MVBITS (elemental), CPU_TIME, DATE_AND_TIME, EVENT_QUERY, EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SIGNAL, SLEEP, SYSTEM, SYSTEM_CLOCK |
770770
| Atomic intrinsic subroutines | ATOMIC_ADD |
771771
| Collective intrinsic subroutines | CO_REDUCE |

flang/include/flang/Evaluate/target.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ class TargetCharacteristics {
102102
bool isPPC() const { return isPPC_; }
103103
void set_isPPC(bool isPPC = false);
104104

105+
bool isOSWindows() const { return isOSWindows_; }
106+
void set_isOSWindows(bool isOSWindows = false) {
107+
isOSWindows_ = isOSWindows;
108+
};
109+
105110
IeeeFeatures &ieeeFeatures() { return ieeeFeatures_; }
106111
const IeeeFeatures &ieeeFeatures() const { return ieeeFeatures_; }
107112

@@ -111,6 +116,7 @@ class TargetCharacteristics {
111116
std::uint8_t align_[common::TypeCategory_enumSize][maxKind]{};
112117
bool isBigEndian_{false};
113118
bool isPPC_{false};
119+
bool isOSWindows_{false};
114120
bool areSubnormalsFlushedToZero_{false};
115121
Rounding roundingMode_{defaultRounding};
116122
std::size_t procedurePointerByteSize_{8};

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ struct IntrinsicLibrary {
257257
llvm::ArrayRef<mlir::Value> args);
258258
void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
259259
void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
260+
mlir::Value genGetGID(mlir::Type resultType,
261+
llvm::ArrayRef<mlir::Value> args);
262+
mlir::Value genGetUID(mlir::Type resultType,
263+
llvm::ArrayRef<mlir::Value> args);
260264
fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
261265
mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
262266
fir::ExtendedValue genIany(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ void genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
4848
mlir::Value values, mlir::Value time);
4949

5050
void genFree(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value ptr);
51+
52+
mlir::Value genGetUID(fir::FirOpBuilder &, mlir::Location);
53+
mlir::Value genGetGID(fir::FirOpBuilder &, mlir::Location);
54+
5155
mlir::Value genMalloc(fir::FirOpBuilder &builder, mlir::Location loc,
5256
mlir::Value size);
5357

flang/include/flang/Runtime/extensions.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
#include <cstddef>
2121
#include <cstdint>
2222

23+
#ifdef _WIN32
24+
// UID and GID don't exist on Windows, these exist to avoid errors.
25+
typedef std::uint32_t uid_t;
26+
typedef std::uint32_t gid_t;
27+
#else
28+
#include "sys/types.h" //pid_t
29+
#endif
30+
2331
extern "C" {
2432

2533
// CALL FLUSH(n) antedates the Fortran 2003 FLUSH statement.
@@ -37,6 +45,12 @@ std::int32_t FORTRAN_PROCEDURE_NAME(iargc)();
3745
void FORTRAN_PROCEDURE_NAME(getarg)(
3846
std::int32_t &n, char *arg, std::int64_t length);
3947

48+
// Calls getgid()
49+
gid_t RTNAME(GetGID)();
50+
51+
// Calls getuid()
52+
uid_t RTNAME(GetUID)();
53+
4054
// GNU extension subroutine GETLOG(C).
4155
void FORTRAN_PROCEDURE_NAME(getlog)(char *name, std::int64_t length);
4256

flang/include/flang/Tools/TargetSetup.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ namespace Fortran::tools {
5959
if (targetTriple.isPPC())
6060
targetCharacteristics.set_isPPC(true);
6161

62+
if (targetTriple.isOSWindows())
63+
targetCharacteristics.set_isOSWindows(true);
64+
6265
// TODO: use target machine data layout to set-up the target characteristics
6366
// type size and alignment info.
6467
}

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,9 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
523523
{{"c", DefaultChar, Rank::scalar, Optionality::required,
524524
common::Intent::Out}},
525525
TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}},
526+
{"getgid", {}, DefaultInt},
526527
{"getpid", {}, DefaultInt},
528+
{"getuid", {}, DefaultInt},
527529
{"huge",
528530
{{"x", SameIntOrReal, Rank::anyOrAssumedRank, Optionality::required,
529531
common::Intent::In, {ArgFlag::canBeMoldNull}}},

flang/lib/Optimizer/Builder/IntrinsicCall.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,9 @@ static constexpr IntrinsicHandler handlers[]{
292292
&I::genGetCwd,
293293
{{{"c", asBox}, {"status", asAddr, handleDynamicOptional}}},
294294
/*isElemental=*/false},
295+
{"getgid", &I::genGetGID},
295296
{"getpid", &I::genGetPID},
297+
{"getuid", &I::genGetUID},
296298
{"iachar", &I::genIchar},
297299
{"iall",
298300
&I::genIall,
@@ -3664,6 +3666,14 @@ void IntrinsicLibrary::genGetCommand(llvm::ArrayRef<fir::ExtendedValue> args) {
36643666
}
36653667
}
36663668

3669+
// GETGID
3670+
mlir::Value IntrinsicLibrary::genGetGID(mlir::Type resultType,
3671+
llvm::ArrayRef<mlir::Value> args) {
3672+
assert(args.size() == 0 && "getgid takes no input");
3673+
return builder.createConvert(loc, resultType,
3674+
fir::runtime::genGetGID(builder, loc));
3675+
}
3676+
36673677
// GETPID
36683678
mlir::Value IntrinsicLibrary::genGetPID(mlir::Type resultType,
36693679
llvm::ArrayRef<mlir::Value> args) {
@@ -3672,6 +3682,14 @@ mlir::Value IntrinsicLibrary::genGetPID(mlir::Type resultType,
36723682
fir::runtime::genGetPID(builder, loc));
36733683
}
36743684

3685+
// GETUID
3686+
mlir::Value IntrinsicLibrary::genGetUID(mlir::Type resultType,
3687+
llvm::ArrayRef<mlir::Value> args) {
3688+
assert(args.size() == 0 && "getgid takes no input");
3689+
return builder.createConvert(loc, resultType,
3690+
fir::runtime::genGetUID(builder, loc));
3691+
}
3692+
36753693
// GET_COMMAND_ARGUMENT
36763694
void IntrinsicLibrary::genGetCommandArgument(
36773695
llvm::ArrayRef<fir::ExtendedValue> args) {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ void fir::runtime::genFree(fir::FirOpBuilder &builder, mlir::Location loc,
129129
builder.createConvert(loc, intPtrTy, ptr));
130130
}
131131

132+
mlir::Value fir::runtime::genGetGID(fir::FirOpBuilder &builder,
133+
mlir::Location loc) {
134+
auto runtimeFunc =
135+
fir::runtime::getRuntimeFunc<mkRTKey(GetGID)>(loc, builder);
136+
137+
return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
138+
}
139+
140+
mlir::Value fir::runtime::genGetUID(fir::FirOpBuilder &builder,
141+
mlir::Location loc) {
142+
auto runtimeFunc =
143+
fir::runtime::getRuntimeFunc<mkRTKey(GetUID)>(loc, builder);
144+
145+
return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
146+
}
147+
132148
mlir::Value fir::runtime::genMalloc(fir::FirOpBuilder &builder,
133149
mlir::Location loc, mlir::Value size) {
134150
auto runtimeFunc =

flang/lib/Semantics/check-call.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,22 @@ bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific,
20422042
return false;
20432043
}
20442044

2045+
bool CheckWindowsIntrinsic(
2046+
const Symbol &intrinsic, evaluate::FoldingContext &foldingContext) {
2047+
parser::ContextualMessages &messages{foldingContext.messages()};
2048+
// TODO: there are other intrinsics that are unsupported on Windows that
2049+
// should be added here.
2050+
if (intrinsic.name() == "getuid") {
2051+
messages.Say(
2052+
"User IDs do not exist on Windows. This function will always return 1"_warn_en_US);
2053+
}
2054+
if (intrinsic.name() == "getgid") {
2055+
messages.Say(
2056+
"Group IDs do not exist on Windows. This function will always return 1"_warn_en_US);
2057+
}
2058+
return true;
2059+
}
2060+
20452061
bool CheckArguments(const characteristics::Procedure &proc,
20462062
evaluate::ActualArguments &actuals, SemanticsContext &context,
20472063
const Scope &scope, bool treatingExternalAsImplicit,

flang/lib/Semantics/check-call.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ bool CheckArguments(const evaluate::characteristics::Procedure &,
4141
bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific,
4242
const evaluate::ActualArguments &actuals,
4343
evaluate::FoldingContext &context);
44+
bool CheckWindowsIntrinsic(
45+
const Symbol &intrinsic, evaluate::FoldingContext &context);
4446
bool CheckArgumentIsConstantExprInRange(
4547
const evaluate::ActualArguments &actuals, int index, int lowerBound,
4648
int upperBound, parser::ContextualMessages &messages);

flang/lib/Semantics/expression.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2916,6 +2916,9 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
29162916
} else {
29172917
resolution = symbol;
29182918
}
2919+
if (resolution && context_.targetCharacteristics().isOSWindows()) {
2920+
semantics::CheckWindowsIntrinsic(*resolution, GetFoldingContext());
2921+
}
29192922
if (!resolution || resolution->attrs().test(semantics::Attr::INTRINSIC)) {
29202923
auto name{resolution ? resolution->name() : ultimate.name()};
29212924
if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(

flang/runtime/extensions.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ extern "C" {
5858

5959
namespace Fortran::runtime {
6060

61+
gid_t RTNAME(GetGID)() {
62+
#ifdef _WIN32
63+
// Group IDs don't exist on Windows, return 1 to avoid errors
64+
return 1;
65+
#else
66+
return getgid();
67+
#endif
68+
}
69+
70+
uid_t RTNAME(GetUID)() {
71+
#ifdef _WIN32
72+
// User IDs don't exist on Windows, return 1 to avoid errors
73+
return 1;
74+
#else
75+
return getuid();
76+
#endif
77+
}
78+
6179
void GetUsernameEnvVar(const char *envName, char *arg, std::int64_t length) {
6280
Descriptor name{*Descriptor::Create(
6381
1, std::strlen(envName) + 1, const_cast<char *>(envName), 0)};
@@ -66,6 +84,7 @@ void GetUsernameEnvVar(const char *envName, char *arg, std::int64_t length) {
6684
RTNAME(GetEnvVariable)
6785
(name, &value, nullptr, false, nullptr, __FILE__, __LINE__);
6886
}
87+
6988
namespace io {
7089
// SUBROUTINE FLUSH(N)
7190
// FLUSH N

flang/test/Semantics/windows.f90

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
! RUN: %if x86_64-registered-target %{ %python %S/test_errors.py %s %flang --target=x86_64-pc-windows-msvc -Werror %}
2+
! RUN: %if aarch64-registered-target %{ %python %S/test_errors.py %s %flang --target=aarch64-pc-windows-msvc -Werror %}
3+
4+
subroutine uid
5+
!WARNING: User IDs do not exist on Windows. This function will always return 1
6+
i = getuid()
7+
end subroutine uid
8+
9+
subroutine gid
10+
!WARNING: Group IDs do not exist on Windows. This function will always return 1
11+
i = getgid()
12+
end subroutine gid

flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ TEST_F(RuntimeCallTest, genGetPID) {
5050
mlir::Value result = fir::runtime::genGetPID(*firBuilder, loc);
5151
checkCallOp(result.getDefiningOp(), "_FortranAGetPID", /*nbArgs=*/0,
5252
/*addLocArgs=*/false);
53-
}
53+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "flang/Optimizer/Builder/Runtime/Intrinsics.h"
2+
#include "RuntimeCallTestBase.h"
3+
#include "gtest/gtest.h"
4+
5+
TEST_F(RuntimeCallTest, genGetGID) {
6+
mlir::Location loc = firBuilder->getUnknownLoc();
7+
mlir::Value result = fir::runtime::genGetGID(*firBuilder, loc);
8+
checkCallOp(result.getDefiningOp(), "_FortranAGetGID", /*nbArgs=*/0,
9+
/*addLocArgs=*/false);
10+
}
11+
12+
TEST_F(RuntimeCallTest, genGetUID) {
13+
mlir::Location loc = firBuilder->getUnknownLoc();
14+
mlir::Value result = fir::runtime::genGetUID(*firBuilder, loc);
15+
checkCallOp(result.getDefiningOp(), "_FortranAGetUID", /*nbArgs=*/0,
16+
/*addLocArgs=*/false);
17+
}

flang/unittests/Optimizer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_flang_unittest(FlangOptimizerTests
2525
Builder/Runtime/CommandTest.cpp
2626
Builder/Runtime/CharacterTest.cpp
2727
Builder/Runtime/DerivedTest.cpp
28+
Builder/Runtime/IntrinsicsTest.cpp
2829
Builder/Runtime/NumericTest.cpp
2930
Builder/Runtime/RaggedTest.cpp
3031
Builder/Runtime/ReductionTest.cpp

0 commit comments

Comments
 (0)