Skip to content

[flang] Implement GETUID and GETGID intrinsics #108017

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flang/docs/Intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ This phase currently supports all the intrinsic procedures listed above but the
| Coarray intrinsic functions | COSHAPE |
| Object characteristic inquiry functions | ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS, PRESENT, RANK, SAME_TYPE, STORAGE_SIZE |
| Type inquiry intrinsic functions | BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT, NEW_LINE, PRECISION, RADIX, RANGE, TINY|
| 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 |
| 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, GETUID, GETGID |
| 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 |
| Atomic intrinsic subroutines | ATOMIC_ADD |
| Collective intrinsic subroutines | CO_REDUCE |
Expand Down
6 changes: 6 additions & 0 deletions flang/include/flang/Evaluate/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ class TargetCharacteristics {
bool isPPC() const { return isPPC_; }
void set_isPPC(bool isPPC = false);

bool isOSWindows() const { return isOSWindows_; }
void set_isOSWindows(bool isOSWindows = false) {
isOSWindows_ = isOSWindows;
};

IeeeFeatures &ieeeFeatures() { return ieeeFeatures_; }
const IeeeFeatures &ieeeFeatures() const { return ieeeFeatures_; }

Expand All @@ -111,6 +116,7 @@ class TargetCharacteristics {
std::uint8_t align_[common::TypeCategory_enumSize][maxKind]{};
bool isBigEndian_{false};
bool isPPC_{false};
bool isOSWindows_{false};
bool areSubnormalsFlushedToZero_{false};
Rounding roundingMode_{defaultRounding};
std::size_t procedurePointerByteSize_{8};
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Optimizer/Builder/IntrinsicCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ struct IntrinsicLibrary {
llvm::ArrayRef<mlir::Value> args);
void genGetCommandArgument(mlir::ArrayRef<fir::ExtendedValue> args);
void genGetEnvironmentVariable(llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genGetGID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args);
mlir::Value genGetUID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args);
fir::ExtendedValue genIall(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genIany(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ void genDateAndTime(fir::FirOpBuilder &, mlir::Location,
void genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value values, mlir::Value time);

mlir::Value genGetUID(fir::FirOpBuilder &, mlir::Location);
mlir::Value genGetGID(fir::FirOpBuilder &, mlir::Location);

void genRandomInit(fir::FirOpBuilder &, mlir::Location, mlir::Value repeatable,
mlir::Value imageDistinct);
void genRandomNumber(fir::FirOpBuilder &, mlir::Location, mlir::Value harvest);
Expand Down
14 changes: 14 additions & 0 deletions flang/include/flang/Runtime/extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
#include <cstddef>
#include <cstdint>

#ifdef _WIN32
// UID and GID don't exist on Windows, these exist to avoid errors.
typedef std::uint32_t uid_t;
typedef std::uint32_t gid_t;
#else
#include "sys/types.h" //pid_t
#endif

extern "C" {

// CALL FLUSH(n) antedates the Fortran 2003 FLUSH statement.
Expand All @@ -35,6 +43,12 @@ std::int32_t FORTRAN_PROCEDURE_NAME(iargc)();
void FORTRAN_PROCEDURE_NAME(getarg)(
std::int32_t &n, char *arg, std::int64_t length);

// Calls getgid()
gid_t RTNAME(GetGID)();

// Calls getuid()
uid_t RTNAME(GetUID)();

// GNU extension subroutine GETLOG(C).
void FORTRAN_PROCEDURE_NAME(getlog)(char *name, std::int64_t length);

Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Tools/TargetSetup.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ namespace Fortran::tools {
if (targetTriple.isPPC())
targetCharacteristics.set_isPPC(true);

if (targetTriple.isOSWindows())
targetCharacteristics.set_isOSWindows(true);

// TODO: use target machine data layout to set-up the target characteristics
// type size and alignment info.
}
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,9 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{{"c", DefaultChar, Rank::scalar, Optionality::required,
common::Intent::Out}},
TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}},
{"getgid", {}, DefaultInt},
{"getpid", {}, DefaultInt},
{"getuid", {}, DefaultInt},
{"huge",
{{"x", SameIntOrReal, Rank::anyOrAssumedRank, Optionality::required,
common::Intent::In, {ArgFlag::canBeMoldNull}}},
Expand Down
18 changes: 18 additions & 0 deletions flang/lib/Optimizer/Builder/IntrinsicCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@ static constexpr IntrinsicHandler handlers[]{
&I::genGetCwd,
{{{"c", asBox}, {"status", asAddr, handleDynamicOptional}}},
/*isElemental=*/false},
{"getgid", &I::genGetGID},
{"getpid", &I::genGetPID},
{"getuid", &I::genGetUID},
{"iachar", &I::genIchar},
{"iall",
&I::genIall,
Expand Down Expand Up @@ -3650,6 +3652,14 @@ void IntrinsicLibrary::genGetCommand(llvm::ArrayRef<fir::ExtendedValue> args) {
}
}

// GETGID
mlir::Value IntrinsicLibrary::genGetGID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 0 && "getgid takes no input");
return builder.createConvert(loc, resultType,
fir::runtime::genGetGID(builder, loc));
}

// GETPID
mlir::Value IntrinsicLibrary::genGetPID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
Expand All @@ -3658,6 +3668,14 @@ mlir::Value IntrinsicLibrary::genGetPID(mlir::Type resultType,
fir::runtime::genGetPID(builder, loc));
}

// GETUID
mlir::Value IntrinsicLibrary::genGetUID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 0 && "getgid takes no input");
return builder.createConvert(loc, resultType,
fir::runtime::genGetUID(builder, loc));
}

// GET_COMMAND_ARGUMENT
void IntrinsicLibrary::genGetCommandArgument(
llvm::ArrayRef<fir::ExtendedValue> args) {
Expand Down
16 changes: 16 additions & 0 deletions flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ void fir::runtime::genEtime(fir::FirOpBuilder &builder, mlir::Location loc,
builder.create<fir::CallOp>(loc, runtimeFunc, args);
}

mlir::Value fir::runtime::genGetGID(fir::FirOpBuilder &builder,
mlir::Location loc) {
auto runtimeFunc =
fir::runtime::getRuntimeFunc<mkRTKey(GetGID)>(loc, builder);

return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
}

mlir::Value fir::runtime::genGetUID(fir::FirOpBuilder &builder,
mlir::Location loc) {
auto runtimeFunc =
fir::runtime::getRuntimeFunc<mkRTKey(GetUID)>(loc, builder);

return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
}

void fir::runtime::genRandomInit(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value repeatable,
mlir::Value imageDistinct) {
Expand Down
16 changes: 16 additions & 0 deletions flang/lib/Semantics/check-call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2020,6 +2020,22 @@ bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific,
return false;
}

bool CheckWindowsIntrinsic(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea. Are these the only two intrinsics which are not supported on Windows? There is at least ACCESS which is also unsupported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably do a check through to see which intrinsics aren't working on Windows and add them all here. That should be a separate patch though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Please add a TODO here

const Symbol &intrinsic, evaluate::FoldingContext &foldingContext) {
parser::ContextualMessages &messages{foldingContext.messages()};
// TODO: there are other intrinsics that are unsupported on Windows that
// should be added here.
if (intrinsic.name() == "getuid") {
messages.Say(
"User IDs do not exist on Windows. This function will always return 1"_warn_en_US);
}
if (intrinsic.name() == "getgid") {
messages.Say(
"Group IDs do not exist on Windows. This function will always return 1"_warn_en_US);
}
return true;
}

bool CheckArguments(const characteristics::Procedure &proc,
evaluate::ActualArguments &actuals, SemanticsContext &context,
const Scope &scope, bool treatingExternalAsImplicit,
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Semantics/check-call.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ bool CheckArguments(const evaluate::characteristics::Procedure &,
bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific,
const evaluate::ActualArguments &actuals,
evaluate::FoldingContext &context);
bool CheckWindowsIntrinsic(
const Symbol &intrinsic, evaluate::FoldingContext &context);
bool CheckArgumentIsConstantExprInRange(
const evaluate::ActualArguments &actuals, int index, int lowerBound,
int upperBound, parser::ContextualMessages &messages);
Expand Down
3 changes: 3 additions & 0 deletions flang/lib/Semantics/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2905,6 +2905,9 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
} else {
resolution = symbol;
}
if (resolution && context_.targetCharacteristics().isOSWindows()) {
semantics::CheckWindowsIntrinsic(*resolution, GetFoldingContext());
}
if (!resolution || resolution->attrs().test(semantics::Attr::INTRINSIC)) {
auto name{resolution ? resolution->name() : ultimate.name()};
if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(
Expand Down
19 changes: 19 additions & 0 deletions flang/runtime/extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,24 @@ extern "C" {

namespace Fortran::runtime {

gid_t RTNAME(GetGID)() {
#ifdef _WIN32
// Group IDs don't exist on Windows, return 1 to avoid errors
return 1;
#else
return getgid();
#endif
}

uid_t RTNAME(GetUID)() {
#ifdef _WIN32
// User IDs don't exist on Windows, return 1 to avoid errors
return 1;
#else
return getuid();
#endif
}

void GetUsernameEnvVar(const char *envName, char *arg, std::int64_t length) {
Descriptor name{*Descriptor::Create(
1, std::strlen(envName) + 1, const_cast<char *>(envName), 0)};
Expand All @@ -66,6 +84,7 @@ void GetUsernameEnvVar(const char *envName, char *arg, std::int64_t length) {
RTNAME(GetEnvVariable)
(name, &value, nullptr, false, nullptr, __FILE__, __LINE__);
}

namespace io {
// SUBROUTINE FLUSH(N)
// FLUSH N
Expand Down
12 changes: 12 additions & 0 deletions flang/test/Semantics/windows.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
! RUN: %python %S/test_errors.py %s %flang --target=x86_64-pc-windows-msvc -Werror
! RUN: %python %S/test_errors.py %s %flang --target=aarch64-pc-windows-msvc -Werror

subroutine uid
!WARNING: User IDs do not exist on Windows. This function will always return 1
i = getuid()
end subroutine uid

subroutine gid
!WARNING: Group IDs do not exist on Windows. This function will always return 1
i = getgid()
end subroutine gid
2 changes: 1 addition & 1 deletion flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ TEST_F(RuntimeCallTest, genGetPID) {
mlir::Value result = fir::runtime::genGetPID(*firBuilder, loc);
checkCallOp(result.getDefiningOp(), "_FortranAGetPID", /*nbArgs=*/0,
/*addLocArgs=*/false);
}
}
17 changes: 17 additions & 0 deletions flang/unittests/Optimizer/Builder/Runtime/IntrinsicsTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "flang/Optimizer/Builder/Runtime/Intrinsics.h"
#include "RuntimeCallTestBase.h"
#include "gtest/gtest.h"

TEST_F(RuntimeCallTest, genGetGID) {
mlir::Location loc = firBuilder->getUnknownLoc();
mlir::Value result = fir::runtime::genGetGID(*firBuilder, loc);
checkCallOp(result.getDefiningOp(), "_FortranAGetGID", /*nbArgs=*/0,
/*addLocArgs=*/false);
}

TEST_F(RuntimeCallTest, genGetUID) {
mlir::Location loc = firBuilder->getUnknownLoc();
mlir::Value result = fir::runtime::genGetUID(*firBuilder, loc);
checkCallOp(result.getDefiningOp(), "_FortranAGetUID", /*nbArgs=*/0,
/*addLocArgs=*/false);
}
1 change: 1 addition & 0 deletions flang/unittests/Optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ add_flang_unittest(FlangOptimizerTests
Builder/Runtime/CommandTest.cpp
Builder/Runtime/CharacterTest.cpp
Builder/Runtime/DerivedTest.cpp
Builder/Runtime/IntrinsicsTest.cpp
Builder/Runtime/NumericTest.cpp
Builder/Runtime/RaggedTest.cpp
Builder/Runtime/ReductionTest.cpp
Expand Down
Loading