diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md index d1f7cd8372e24..1fdf22daf3688 100644 --- a/flang/docs/Intrinsics.md +++ b/flang/docs/Intrinsics.md @@ -707,6 +707,7 @@ MALLOC ``` CALL FDATE(TIME) CALL GETLOG(USRNAME) +CALL GETENV(NAME [, VALUE, LENGTH, STATUS, TRIM_NAME, ERRMSG ]) ``` ## Intrinsic Procedure Name Resolution @@ -768,7 +769,7 @@ This phase currently supports all the intrinsic procedures listed above but the | 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 | -| Library subroutines | FDATE, GETLOG | +| Library subroutines | FDATE, GETLOG, GETENV | ### Intrinsic Function Folding @@ -999,4 +1000,4 @@ PROGRAM example_getcwd PRINT *, cwd PRINT *, status END PROGRAM -``` \ No newline at end of file +``` diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp index 80752d02b5baf..c5e3d99396734 100644 --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -998,6 +998,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{ // compatibility and builtins. static const std::pair genericAlias[]{ {"and", "iand"}, + {"getenv", "get_environment_variable"}, {"imag", "aimag"}, {"lshift", "shiftl"}, {"or", "ior"}, @@ -2594,7 +2595,8 @@ bool IntrinsicProcTable::Implementation::IsIntrinsicFunction( return name == "__builtin_c_loc" || name == "null"; } bool IntrinsicProcTable::Implementation::IsIntrinsicSubroutine( - const std::string &name) const { + const std::string &name0) const { + const std::string &name{ResolveAlias(name0)}; auto subrRange{subroutines_.equal_range(name)}; if (subrRange.first != subrRange.second) { return true; @@ -3151,7 +3153,8 @@ std::optional IntrinsicProcTable::Implementation::Probe( } if (call.isSubroutineCall) { - auto subrRange{subroutines_.equal_range(call.name)}; + const std::string &name{ResolveAlias(call.name)}; + auto subrRange{subroutines_.equal_range(name)}; for (auto iter{subrRange.first}; iter != subrRange.second; ++iter) { if (auto specificCall{iter->second->Match( call, defaults_, arguments, context, builtinsScope_)}) { diff --git a/flang/test/Lower/Intrinsics/get_environment_variable.f90 b/flang/test/Lower/Intrinsics/get_environment_variable.f90 index 41634aaa97f4d..cc342940f95ff 100644 --- a/flang/test/Lower/Intrinsics/get_environment_variable.f90 +++ b/flang/test/Lower/Intrinsics/get_environment_variable.f90 @@ -161,3 +161,165 @@ subroutine all_arguments(name, value, length, status, trim_name, errmsg) ! CHECK-64: %[[status:.*]] = fir.convert %[[status32]] : (i32) -> i64 ! CHECK: fir.store %[[status]] to %[[statusArg]] : !fir.ref end subroutine all_arguments + + +! CHECK-LABEL: func @_QPgetenv_name_only( +! CHECK-SAME: %[[nameArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "name"}) { +subroutine getenv_name_only(name) + character(len=32) :: name + call getenv(name) +! CHECK-NOT: fir.call @_FortranAGetEnvVariable +! CHECK-NEXT: return +end subroutine getenv_name_only + +! CHECK-LABEL: func @_QPgetenv_name_and_value_only( +! CHECK-SAME: %[[nameArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "name"}, +! CHECK-SAME: %[[valueArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "value"}) { +subroutine getenv_name_and_value_only(name, value) + character(len=32) :: name, value + call getenv(name, value) +! CHECK: %[[nameUnbox:.*]]:2 = fir.unboxchar %[[nameArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[nameCast:.*]] = fir.convert %[[nameUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[valueUnbox:.*]]:2 = fir.unboxchar %[[valueArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[valueCast:.*]] = fir.convert %[[valueUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameBox:.*]] = fir.embox %[[nameCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %[[valueBox:.*]] = fir.embox %[[valueCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %true = arith.constant true +! CHECK-NEXT: %[[length:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[errmsg:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[sourceFileString:.*]] = fir.address_of(@_QQcl{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 11]] : i32 +! CHECK-NEXT: %[[name:.*]] = fir.convert %[[nameBox]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[value:.*]] = fir.convert %[[valueBox]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-NEXT: %{{[0-9]+}} = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %true, %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK-NEXT: return +end subroutine getenv_name_and_value_only + +! CHECK-LABEL: func @_QPgetenv_name_and_length_only( +! CHECK-SAME: %[[nameArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "name"}, +! CHECK-SAME: %[[lengthArg:.*]]: !fir.ref {fir.bindc_name = "length"}) { +subroutine getenv_name_and_length_only(name, length) + character(len=32) :: name + integer :: length + call getenv(name, LENGTH=length) +! CHECK: %[[nameUnbox:.*]]:2 = fir.unboxchar %[[nameArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[nameCast:.*]] = fir.convert %[[nameUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameBox:.*]] = fir.embox %[[nameCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %[[lengthBox:.*]] = fir.embox %arg1 : (!fir.ref) -> !fir.box +! CHECK-NEXT: %true = arith.constant true +! CHECK-NEXT: %[[value:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[errmsg:.*]] = fir.absent !fir.box +! CHECK: %[[sourceFileString:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 9]] : i32 +! CHECK-NEXT: %[[name:.*]] = fir.convert %[[nameBox]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[length:.*]] = fir.convert %[[lengthBox]] : (!fir.box) -> !fir.box +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-NEXT: %{{.*}} = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %true, %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +end subroutine getenv_name_and_length_only + +! CHECK-LABEL: func @_QPgetenv_name_and_status_only( +! CHECK-SAME: %[[nameArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "name"}, +! CHECK-SAME: %[[statusArg:.*]]: !fir.ref {fir.bindc_name = "status"}) { +subroutine getenv_name_and_status_only(name, status) + character(len=32) :: name + integer :: status + call getenv(name, STATUS=status) +! CHECK: %[[nameUnbox:.*]]:2 = fir.unboxchar %[[nameArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[nameCast:.*]] = fir.convert %[[nameUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameBox:.*]] = fir.embox %[[nameCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %true = arith.constant true +! CHECK-NEXT: %[[value:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[length:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[errmsg:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[sourceFileString:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 9]] : i32 +! CHECK-NEXT: %[[name:.*]] = fir.convert %[[nameBox]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %[[status:.*]] = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %true, %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %[[status32:.*]] = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %true, %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64: %[[status:.*]] = fir.convert %[[status32]] : (i32) -> i64 +! CHECK: fir.store %[[status]] to %[[statusArg]] : !fir.ref +end subroutine getenv_name_and_status_only + +! CHECK-LABEL: func @_QPgetenv_name_and_trim_name_only( +! CHECK-SAME: %[[nameArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "name"}, +! CHECK-32-SAME: %[[trimNameArg:.*]]: !fir.ref> {fir.bindc_name = "trim_name"}) { +! CHECK-64-SAME: %[[trimNameArg:.*]]: !fir.ref> {fir.bindc_name = "trim_name"}) { +subroutine getenv_name_and_trim_name_only(name, trim_name) + character(len=32) :: name + logical :: trim_name + call getenv(name, TRIM_NAME=trim_name) + ! CHECK-NOT: fir.call @_FortranAGetEnvVariable + ! CHECK-NEXT: return +end subroutine getenv_name_and_trim_name_only + +! CHECK-LABEL: func @_QPgetenv_name_and_errmsg_only( +! CHECK-SAME: %[[nameArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "name"}, +! CHECK-SAME: %[[errmsgArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "errmsg"}) { +subroutine getenv_name_and_errmsg_only(name, errmsg) + character(len=32) :: name, errmsg + call getenv(name, ERRMSG=errmsg) +! CHECK: %[[errmsgUnbox:.*]]:2 = fir.unboxchar %[[errmsgArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[errmsgCast:.*]] = fir.convert %[[errmsgUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameUnbox:.*]]:2 = fir.unboxchar %[[nameArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[nameCast:.*]] = fir.convert %[[nameUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameBox:.*]] = fir.embox %[[nameCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %[[errmsgBox:.*]] = fir.embox %[[errmsgCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %true = arith.constant true +! CHECK-NEXT: %[[value:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[length:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[sourceFileString:.*]] = fir.address_of(@_QQclX{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 11]] : i32 +! CHECK-NEXT: %[[name:.*]] = fir.convert %[[nameBox]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[errmsg:.*]] = fir.convert %[[errmsgBox]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-NEXT: %{{[0-9]+}} = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %true, %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK-NEXT: return +end subroutine getenv_name_and_errmsg_only + +! CHECK-LABEL: func @_QPgetenv_all_arguments( +! CHECK-SAME: %[[nameArg:[^:]*]]: !fir.boxchar<1> {fir.bindc_name = "name"}, +! CHECK-SAME: %[[valueArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "value"}, +! CHECK-SAME: %[[lengthArg:[^:]*]]: !fir.ref {fir.bindc_name = "length"}, +! CHECK-SAME: %[[statusArg:.*]]: !fir.ref {fir.bindc_name = "status"}, +! CHECK-32-SAME: %[[trimNameArg:.*]]: !fir.ref> {fir.bindc_name = "trim_name"}, +! CHECK-64-SAME: %[[trimNameArg:.*]]: !fir.ref> {fir.bindc_name = "trim_name"}, +! CHECK-SAME: %[[errmsgArg:.*]]: !fir.boxchar<1> {fir.bindc_name = "errmsg"}) { +subroutine getenv_all_arguments(name, value, length, status, trim_name, errmsg) + character(len=32) :: name, value, errmsg + integer :: length, status + logical :: trim_name + call getenv(name, value, length, status, trim_name, errmsg) +! CHECK: %[[errmsgUnbox:.*]]:2 = fir.unboxchar %[[errmsgArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[errmsgCast:.*]] = fir.convert %[[errmsgUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameUnbox:.*]]:2 = fir.unboxchar %[[nameArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[nameCast:.*]] = fir.convert %[[nameUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[valueUnbox:.*]]:2 = fir.unboxchar %[[valueArg]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK-NEXT: %[[valueCast:.*]] = fir.convert %[[valueUnbox]]#0 : (!fir.ref>) -> !fir.ref> +! CHECK-NEXT: %[[nameBoxed:.*]] = fir.embox %[[nameCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %[[valueBoxed:.*]] = fir.embox %[[valueCast]] : (!fir.ref>) -> !fir.box> +! CHECK-NEXT: %[[lengthBoxed:.*]] = fir.embox %[[lengthArg]] : (!fir.ref) -> !fir.box +! CHECK-NEXT: %[[errmsgBoxed:.*]] = fir.embox %[[errmsgCast]] : (!fir.ref>) -> !fir.box> +! CHECK: %[[trimName:.*]] = fir.if %{{.*}} -> (i1) { +! CHECK-32-NEXT: %[[trimNameLoaded:.*]] = fir.load %[[trimNameArg]] : !fir.ref> +! CHECK-64-NEXT: %[[trimNameLoaded:.*]] = fir.load %[[trimNameArg]] : !fir.ref> +! CHECK-32-NEXT: %[[trimCast:.*]] = fir.convert %[[trimNameLoaded]] : (!fir.logical<4>) -> i1 +! CHECK-64-NEXT: %[[trimCast:.*]] = fir.convert %[[trimNameLoaded]] : (!fir.logical<8>) -> i1 +! CHECK-NEXT: fir.result %[[trimCast]] : i1 +! CHECK-NEXT: } else { +! CHECK-NEXT: %[[trueVal:.*]] = arith.constant true +! CHECK-NEXT: fir.result %[[trueVal]] : i1 +! CHECK-NEXT: } +! CHECK: %[[sourceFileString:.*]] = fir.address_of(@_QQclX[[fileString:.*]]) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 22]] : i32 +! CHECK-NEXT: %[[name:.*]] = fir.convert %[[nameBoxed]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[value:.*]] = fir.convert %[[valueBoxed]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[length:.*]] = fir.convert %[[lengthBoxed]] : (!fir.box) -> !fir.box +! CHECK-NEXT: %[[errmsg:.*]] = fir.convert %[[errmsgBoxed]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %[[status:.*]] = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %[[trimName]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %[[status32:.*]] = fir.call @_FortranAGetEnvVariable(%[[name]], %[[value]], %[[length]], %[[trimName]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) {{.*}}: (!fir.box, !fir.box, !fir.box, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64: %[[status:.*]] = fir.convert %[[status32]] : (i32) -> i64 +! CHECK: fir.store %[[status]] to %[[statusArg]] : !fir.ref +end subroutine getenv_all_arguments