From eb7a02ea009b6a2aa3689ee92905fb6acea905fc Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Fri, 1 Jul 2022 11:43:20 +0000 Subject: [PATCH] [flang] Single entry point for GET_COMMAND_ARGUMENT This patch refactors the runtime support for GET_COMMAND_ARGUMENT to have a single entry point instead of 2. It also updates lowering accordingly. This makes it easier to handle dynamically optional arguments. See also https://reviews.llvm.org/D118777 Differential Revision: https://reviews.llvm.org/D130475 --- .../flang/Optimizer/Builder/Runtime/Command.h | 20 ++-- flang/include/flang/Runtime/command.h | 13 +-- flang/lib/Lower/IntrinsicCall.cpp | 62 +++++------ .../lib/Optimizer/Builder/Runtime/Command.cpp | 34 +++--- flang/runtime/command.cpp | 101 ++++++++++-------- .../get_command_argument-optional.f90 | 18 ++-- .../Lower/Intrinsics/get_command_argument.f90 | 58 ++++++---- flang/test/Runtime/no-cpp-dep.c | 10 +- .../Optimizer/Builder/Runtime/CommandTest.cpp | 28 ++--- flang/unittests/Runtime/CommandTest.cpp | 67 ++++++------ 10 files changed, 194 insertions(+), 217 deletions(-) diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Command.h b/flang/include/flang/Optimizer/Builder/Runtime/Command.h index fb829f81b797..7df67c1527c0 100644 --- a/flang/include/flang/Optimizer/Builder/Runtime/Command.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Command.h @@ -23,19 +23,13 @@ namespace fir::runtime { /// Generate call to COMMAND_ARGUMENT_COUNT intrinsic runtime routine. mlir::Value genCommandArgumentCount(fir::FirOpBuilder &, mlir::Location); -/// Generate a call to ArgumentValue runtime function which implements -/// the part of GET_COMMAND_ARGUMENT related to VALUE, ERRMSG, and STATUS. -/// \p value and \p errmsg must be fir.box that can be absent (but not null -/// mlir values). The status value is returned. -mlir::Value genArgumentValue(fir::FirOpBuilder &, mlir::Location, - mlir::Value number, mlir::Value value, - mlir::Value errmsg); - -/// Generate a call to ArgumentLength runtime function which implements -/// the part of GET_COMMAND_ARGUMENT related to LENGTH. -/// It returns the length of the \p number command arguments. -mlir::Value genArgumentLength(fir::FirOpBuilder &, mlir::Location, - mlir::Value number); +/// Generate a call to the GetCommandArgument runtime function which implements +/// the GET_COMMAND_ARGUMENT intrinsic. +/// \p value, \p length and \p errmsg must be fir.box that can be absent (but +/// not null mlir values). The status value is returned. +mlir::Value genGetCommandArgument(fir::FirOpBuilder &, mlir::Location, + mlir::Value number, mlir::Value value, + mlir::Value length, mlir::Value errmsg); /// Generate a call to EnvVariableValue runtime function which implements /// the part of GET_ENVIRONMENT_ARGUMENT related to VALUE, ERRMSG, and STATUS. diff --git a/flang/include/flang/Runtime/command.h b/flang/include/flang/Runtime/command.h index 55fe39323b92..74b3d0b9992b 100644 --- a/flang/include/flang/Runtime/command.h +++ b/flang/include/flang/Runtime/command.h @@ -32,17 +32,12 @@ std::int32_t RTNAME(GetCommand)(const Descriptor *command = nullptr, const char *sourceFile = nullptr, int line = 0); // 16.9.83 GET_COMMAND_ARGUMENT -// We're breaking up the interface into several different functions, since most -// of the parameters are optional. - // Try to get the value of the n'th argument. // Returns a STATUS as described in the standard. -std::int32_t RTNAME(ArgumentValue)( - std::int32_t n, const Descriptor *value, const Descriptor *errmsg); - -// Try to get the significant length of the n'th argument. -// Returns 0 if it doesn't manage. -std::int64_t RTNAME(ArgumentLength)(std::int32_t n); +std::int32_t RTNAME(GetCommandArgument)(std::int32_t n, + const Descriptor *argument = nullptr, const Descriptor *length = nullptr, + const Descriptor *errmsg = nullptr, const char *sourceFile = nullptr, + int line = 0); // 16.9.84 GET_ENVIRONMENT_VARIABLE // We're breaking up the interface into several different functions, since most diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp index 826404e80c53..0cb5efccc567 100644 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -769,8 +769,8 @@ static constexpr IntrinsicHandler handlers[]{ &I::genGetCommandArgument, {{{"number", asValue}, {"value", asBox, handleDynamicOptional}, - {"length", asAddr}, - {"status", asAddr}, + {"length", asBox, handleDynamicOptional}, + {"status", asAddr, handleDynamicOptional}, {"errmsg", asBox, handleDynamicOptional}}}, /*isElemental=*/false}, {"get_environment_variable", @@ -2778,38 +2778,32 @@ void IntrinsicLibrary::genGetCommandArgument( if (!number) fir::emitFatalError(loc, "expected NUMBER parameter"); - if (isStaticallyPresent(value) || isStaticallyPresent(status) || - isStaticallyPresent(errmsg)) { - mlir::Type boxNoneTy = fir::BoxType::get(builder.getNoneType()); - mlir::Value valBox = - isStaticallyPresent(value) - ? fir::getBase(value) - : builder.create(loc, boxNoneTy).getResult(); - mlir::Value errBox = - isStaticallyPresent(errmsg) - ? fir::getBase(errmsg) - : builder.create(loc, boxNoneTy).getResult(); - mlir::Value stat = - fir::runtime::genArgumentValue(builder, loc, number, valBox, errBox); - if (isStaticallyPresent(status)) { - mlir::Value statAddr = fir::getBase(status); - mlir::Value statIsPresentAtRuntime = - builder.genIsNotNullAddr(loc, statAddr); - builder.genIfThen(loc, statIsPresentAtRuntime) - .genThen( - [&]() { builder.createStoreWithConvert(loc, stat, statAddr); }) - .end(); - } - } - if (isStaticallyPresent(length)) { - mlir::Value lenAddr = fir::getBase(length); - mlir::Value lenIsPresentAtRuntime = builder.genIsNotNullAddr(loc, lenAddr); - builder.genIfThen(loc, lenIsPresentAtRuntime) - .genThen([&]() { - mlir::Value len = - fir::runtime::genArgumentLength(builder, loc, number); - builder.createStoreWithConvert(loc, len, lenAddr); - }) + // If none of the optional parameters are present, do nothing. + if (!isStaticallyPresent(value) && !isStaticallyPresent(length) && + !isStaticallyPresent(status) && !isStaticallyPresent(errmsg)) + return; + + mlir::Type boxNoneTy = fir::BoxType::get(builder.getNoneType()); + mlir::Value valBox = + isStaticallyPresent(value) + ? fir::getBase(value) + : builder.create(loc, boxNoneTy).getResult(); + mlir::Value lenBox = + isStaticallyPresent(length) + ? fir::getBase(length) + : builder.create(loc, boxNoneTy).getResult(); + mlir::Value errBox = + isStaticallyPresent(errmsg) + ? fir::getBase(errmsg) + : builder.create(loc, boxNoneTy).getResult(); + mlir::Value stat = fir::runtime::genGetCommandArgument( + builder, loc, number, valBox, lenBox, errBox); + if (isStaticallyPresent(status)) { + mlir::Value statAddr = fir::getBase(status); + mlir::Value statIsPresentAtRuntime = + builder.genIsNotNullAddr(loc, statAddr); + builder.genIfThen(loc, statIsPresentAtRuntime) + .genThen([&]() { builder.createStoreWithConvert(loc, stat, statAddr); }) .end(); } } diff --git a/flang/lib/Optimizer/Builder/Runtime/Command.cpp b/flang/lib/Optimizer/Builder/Runtime/Command.cpp index 9e12f649f95e..622701380377 100644 --- a/flang/lib/Optimizer/Builder/Runtime/Command.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Command.cpp @@ -32,27 +32,19 @@ mlir::Value fir::runtime::genCommandArgumentCount(fir::FirOpBuilder &builder, return builder.create(loc, argumentCountFunc).getResult(0); } -mlir::Value fir::runtime::genArgumentValue(fir::FirOpBuilder &builder, - mlir::Location loc, - mlir::Value number, - mlir::Value value, - mlir::Value errmsg) { - auto argumentValueFunc = - fir::runtime::getRuntimeFunc(loc, builder); - llvm::SmallVector args = fir::runtime::createArguments( - builder, loc, argumentValueFunc.getFunctionType(), number, value, errmsg); - return builder.create(loc, argumentValueFunc, args).getResult(0); -} - -mlir::Value fir::runtime::genArgumentLength(fir::FirOpBuilder &builder, - mlir::Location loc, - mlir::Value number) { - auto argumentLengthFunc = - fir::runtime::getRuntimeFunc(loc, builder); - llvm::SmallVector args = fir::runtime::createArguments( - builder, loc, argumentLengthFunc.getFunctionType(), number); - return builder.create(loc, argumentLengthFunc, args) - .getResult(0); +mlir::Value fir::runtime::genGetCommandArgument( + fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value number, + mlir::Value value, mlir::Value length, mlir::Value errmsg) { + auto runtimeFunc = + fir::runtime::getRuntimeFunc(loc, builder); + mlir::FunctionType runtimeFuncTy = runtimeFunc.getFunctionType(); + mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc); + mlir::Value sourceLine = + fir::factory::locationToLineNo(builder, loc, runtimeFuncTy.getInput(5)); + llvm::SmallVector args = + fir::runtime::createArguments(builder, loc, runtimeFuncTy, number, value, + length, errmsg, sourceFile, sourceLine); + return builder.create(loc, runtimeFunc, args).getResult(0); } mlir::Value fir::runtime::genEnvVariableValue( diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp index fe54da2e6d68..6ee012f85254 100644 --- a/flang/runtime/command.cpp +++ b/flang/runtime/command.cpp @@ -37,15 +37,6 @@ static std::int64_t StringLength(const char *string) { } } -std::int64_t RTNAME(ArgumentLength)(std::int32_t n) { - if (n < 0 || n >= executionEnvironment.argc || - !executionEnvironment.argv[n]) { - return 0; - } - - return StringLength(executionEnvironment.argv[n]); -} - static bool IsValidCharDescriptor(const Descriptor *value) { return value && value->IsAllocated() && value->type() == TypeCode(TypeCategory::Character, 1) && @@ -107,27 +98,12 @@ static std::int32_t CheckAndCopyToDescriptor(const Descriptor *value, return stat; } -std::int32_t RTNAME(ArgumentValue)( - std::int32_t n, const Descriptor *value, const Descriptor *errmsg) { - if (IsValidCharDescriptor(value)) { - FillWithSpaces(*value); - } - - if (n < 0 || n >= executionEnvironment.argc) { - return ToErrmsg(errmsg, StatInvalidArgumentNumber); - } - - if (IsValidCharDescriptor(value)) { - const char *arg{executionEnvironment.argv[n]}; - std::int64_t argLen{StringLength(arg)}; - if (argLen <= 0) { - return ToErrmsg(errmsg, StatMissingArgument); - } - - return CopyToDescriptor(*value, arg, argLen, errmsg); - } - - return StatOk; +static void StoreLengthToDescriptor( + const Descriptor *length, std::int64_t value, Terminator &terminator) { + auto typeCode{length->type().GetCategoryAndKind()}; + int kind{typeCode->second}; + Fortran::runtime::ApplyIntegerKind( + kind, terminator, *length, /* atIndex = */ 0, value); } template struct FitsInIntegerKind { @@ -137,17 +113,55 @@ template struct FitsInIntegerKind { } }; -std::int32_t RTNAME(GetCommand)(const Descriptor *value, +static bool FitsInDescriptor( + const Descriptor *length, std::int64_t value, Terminator &terminator) { + auto typeCode{length->type().GetCategoryAndKind()}; + int kind{typeCode->second}; + return Fortran::runtime::ApplyIntegerKind( + kind, terminator, value); +} + +std::int32_t RTNAME(GetCommandArgument)(std::int32_t n, const Descriptor *value, const Descriptor *length, const Descriptor *errmsg, const char *sourceFile, int line) { Terminator terminator{sourceFile, line}; - auto storeLength = [&](std::int64_t value) { - auto typeCode{length->type().GetCategoryAndKind()}; - int kind{typeCode->second}; - Fortran::runtime::ApplyIntegerKind( - kind, terminator, *length, /* atIndex = */ 0, value); - }; + if (value) { + RUNTIME_CHECK(terminator, IsValidCharDescriptor(value)); + FillWithSpaces(*value); + } + + // Store 0 in case we error out later on. + if (length) { + RUNTIME_CHECK(terminator, IsValidIntDescriptor(length)); + StoreLengthToDescriptor(length, 0, terminator); + } + + if (n < 0 || n >= executionEnvironment.argc) { + return ToErrmsg(errmsg, StatInvalidArgumentNumber); + } + + const char *arg{executionEnvironment.argv[n]}; + std::int64_t argLen{StringLength(arg)}; + if (argLen <= 0) { + return ToErrmsg(errmsg, StatMissingArgument); + } + + if (length && FitsInDescriptor(length, argLen, terminator)) { + StoreLengthToDescriptor(length, argLen, terminator); + } + + if (value) { + return CopyToDescriptor(*value, arg, argLen, errmsg); + } + + return StatOk; +} + +std::int32_t RTNAME(GetCommand)(const Descriptor *value, + const Descriptor *length, const Descriptor *errmsg, const char *sourceFile, + int line) { + Terminator terminator{sourceFile, line}; if (value) { RUNTIME_CHECK(terminator, IsValidCharDescriptor(value)); @@ -156,7 +170,7 @@ std::int32_t RTNAME(GetCommand)(const Descriptor *value, // Store 0 in case we error out later on. if (length) { RUNTIME_CHECK(terminator, IsValidIntDescriptor(length)); - storeLength(0); + StoreLengthToDescriptor(length, 0, terminator); } auto shouldContinue = [&](std::int32_t stat) -> bool { @@ -192,15 +206,8 @@ std::int32_t RTNAME(GetCommand)(const Descriptor *value, } } - auto fitsInLength = [&](std::int64_t value) -> bool { - auto typeCode{length->type().GetCategoryAndKind()}; - int kind{typeCode->second}; - return Fortran::runtime::ApplyIntegerKind( - kind, terminator, value); - }; - - if (length && fitsInLength(offset)) { - storeLength(offset); + if (length && FitsInDescriptor(length, offset, terminator)) { + StoreLengthToDescriptor(length, offset, terminator); } // value += spaces for padding diff --git a/flang/test/Lower/Intrinsics/get_command_argument-optional.f90 b/flang/test/Lower/Intrinsics/get_command_argument-optional.f90 index bd707f1f13f7..9268a7b3b5f7 100644 --- a/flang/test/Lower/Intrinsics/get_command_argument-optional.f90 +++ b/flang/test/Lower/Intrinsics/get_command_argument-optional.f90 @@ -19,25 +19,25 @@ subroutine test(number, value, length, status, errmsg) ! CHECK: %[[valueReboxed:.*]] = fir.embox %[[valueUnboxed]]#0 typeparams %[[valueUnboxed]]#1 : (!fir.ref>, index) -> !fir.box> ! CHECK: %[[valueAbsent:.*]] = fir.absent !fir.box> ! CHECK: %[[valueOrAbsent:.*]] = arith.select %[[valueIsPresent]], %[[valueReboxed]], %[[valueAbsent]] : !fir.box> +! CHECK: %[[lengthIsPresent:.*]] = fir.is_present %[[lengthParam]] : (!fir.ref) -> i1 +! CHECK: %[[lengthBoxed:.*]] = fir.embox %[[lengthParam]] : (!fir.ref) -> !fir.box +! CHECK: %[[lengthAbsent:.*]] = fir.absent !fir.box +! CHECK: %[[lengthOrAbsent:.*]] = arith.select %[[lengthIsPresent]], %[[lengthBoxed]], %[[lengthAbsent]] : !fir.box ! CHECK: %[[errmsgIsPresent:.*]] = fir.is_present %[[errmsgUnboxed]]#0 : (!fir.ref>) -> i1 ! CHECK: %[[errmsgReboxed:.*]] = fir.embox %[[errmsgUnboxed]]#0 typeparams %[[errmsgUnboxed]]#1 : (!fir.ref>, index) -> !fir.box> ! CHECK: %[[errmsgAbsent:.*]] = fir.absent !fir.box> ! CHECK: %[[errmsgOrAbsent:.*]] = arith.select %[[errmsgIsPresent]], %[[errmsgReboxed]], %[[errmsgAbsent]] : !fir.box> +! CHECK: %[[sourceFileString:.*]] = fir.address_of(@_QQcl{{.*}}) : !fir.ref> +! CHECK: %[[sourceLine:.*]] = arith.constant [[# @LINE - 17]] : i32 ! CHECK: %[[value:.*]] = fir.convert %[[valueOrAbsent]] : (!fir.box>) -> !fir.box +! CHECK: %[[length:.*]] = fir.convert %[[lengthOrAbsent]] : (!fir.box) -> !fir.box ! CHECK: %[[errmsg:.*]] = fir.convert %[[errmsgOrAbsent]] : (!fir.box>) -> !fir.box -! CHECK: %[[status:.*]] = fir.call @_FortranAArgumentValue(%[[number]], %[[value]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 +! CHECK: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK: %[[status:.*]] = fir.call @_FortranAGetCommandArgument(%[[number]], %[[value]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 ! CHECK: %[[statusI64:.*]] = fir.convert %[[statusParam]] : (!fir.ref) -> i64 ! CHECK: %[[zero:.*]] = arith.constant 0 : i64 ! CHECK: %[[statusIsNonNull:.*]] = arith.cmpi ne, %[[statusI64]], %[[zero]] : i64 ! CHECK: fir.if %[[statusIsNonNull]] { ! CHECK: fir.store %[[status]] to %[[statusParam]] : !fir.ref ! CHECK: } -! CHECK: %[[lengthI64:.*]] = fir.convert %[[lengthParam]] : (!fir.ref) -> i64 -! CHECK: %[[zero2:.*]] = arith.constant 0 : i64 -! CHECK: %[[lengthIsNonNull:.*]] = arith.cmpi ne, %[[lengthI64]], %[[zero2]] : i64 -! CHECK: fir.if %[[lengthIsNonNull]] { -! CHECK: %[[length:.*]] = fir.call @_FortranAArgumentLength(%[[number]]) : (i32) -> i64 -! CHECK: %[[lengthTrunc:.*]] = fir.convert %[[length]] : (i64) -> i32 -! CHECK: fir.store %[[lengthTrunc]] to %[[lengthParam]] : !fir.ref -! CHECK: } end subroutine diff --git a/flang/test/Lower/Intrinsics/get_command_argument.f90 b/flang/test/Lower/Intrinsics/get_command_argument.f90 index 3dc3f9ac20cd..1b26e3493a63 100644 --- a/flang/test/Lower/Intrinsics/get_command_argument.f90 +++ b/flang/test/Lower/Intrinsics/get_command_argument.f90 @@ -6,8 +6,7 @@ subroutine number_only(num) integer :: num call get_command_argument(num) -! CHECK-NOT: fir.call @_FortranAArgumentValue -! CHECK-NOT: fir.call @_FortranAArgumentLength +! CHECK-NOT: fir.call @_FortranAGetCommandArgument ! CHECK-NEXT: return end subroutine number_only @@ -21,12 +20,15 @@ call get_command_argument(num, value) ! CHECK-NEXT: %[[valueLength:.*]] = arith.constant 32 : index ! CHECK-NEXT: %[[numUnbox:.*]] = fir.load %[[num]] : !fir.ref ! CHECK-NEXT: %[[valueBoxed:.*]] = fir.embox %[[valueUnboxed]]#0 typeparams %[[valueLength]] : (!fir.ref>, index) -> !fir.box> +! 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 - 8]] : i32 ! CHECK-64-NEXT: %[[numCast:.*]] = fir.convert %[[numUnbox]] : (i64) -> i32 ! CHECK-NEXT: %[[valueCast:.*]] = fir.convert %[[valueBoxed]] : (!fir.box>) -> !fir.box -! CHECK-32-NEXT: %{{[0-9]+}} = fir.call @_FortranAArgumentValue(%[[numUnbox]], %[[valueCast]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 -! CHECK-64-NEXT: %{{[0-9]+}} = fir.call @_FortranAArgumentValue(%[[numCast]], %[[valueCast]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 -! CHECK-NOT: fir.call @_FortranAArgumentLength +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %{{[0-9]+}} = fir.call @_FortranAGetCommandArgument(%[[numUnbox]], %[[valueCast]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %{{[0-9]+}} = fir.call @_FortranAGetCommandArgument(%[[numCast]], %[[valueCast]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 end subroutine number_and_value_only ! CHECK-LABEL: func @_QPall_arguments( @@ -41,19 +43,19 @@ subroutine all_arguments(num, value, length, status, errmsg) ! CHECK-NEXT: %[[valueLen:.*]] = arith.constant 32 : index ! CHECK-NEXT: %[[numUnboxed:.*]] = fir.load %[[num]] : !fir.ref ! CHECK-NEXT: %[[valueBoxed:.*]] = fir.embox %[[valueUnboxed]]#0 typeparams %[[valueLen]] : (!fir.ref>, index) -> !fir.box> +! CHECK-NEXT: %[[lengthBoxed:.*]] = fir.embox %[[length]] : (!fir.ref) -> !fir.box ! CHECK-NEXT: %[[errmsgBoxed:.*]] = fir.embox %[[errmsgUnboxed]]#0 typeparams %[[errmsgLen]] : (!fir.ref>, index) -> !fir.box> +! CHECK-NEXT: %[[sourceFileString:.*]] = fir.address_of(@_QQcl{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 10]] : i32 ! CHECK-64-NEXT: %[[numCast:.*]] = fir.convert %[[numUnboxed]] : (i64) -> i32 ! CHECK-NEXT: %[[valueBuffer:.*]] = fir.convert %[[valueBoxed]] : (!fir.box>) -> !fir.box +! CHECK-NEXT: %[[lengthBuffer:.*]] = fir.convert %[[lengthBoxed]] : (!fir.box) -> !fir.box ! CHECK-NEXT: %[[errmsgBuffer:.*]] = fir.convert %[[errmsgBoxed]] : (!fir.box>) -> !fir.box -! CHECK-32-NEXT: %[[statusResult:.*]] = fir.call @_FortranAArgumentValue(%[[numUnboxed]], %[[valueBuffer]], %[[errmsgBuffer]]) : (i32, !fir.box, !fir.box) -> i32 -! CHECK-64-NEXT: %[[statusResult32:.*]] = fir.call @_FortranAArgumentValue(%[[numCast]], %[[valueBuffer]], %[[errmsgBuffer]]) : (i32, !fir.box, !fir.box) -> i32 +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %[[statusResult:.*]] = fir.call @_FortranAGetCommandArgument(%[[numUnboxed]], %[[valueBuffer]], %[[lengthBuffer]], %[[errmsgBuffer]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %[[statusResult32:.*]] = fir.call @_FortranAGetCommandArgument(%[[numCast]], %[[valueBuffer]], %[[lengthBuffer]], %[[errmsgBuffer]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 ! CHECK-64: %[[statusResult:.*]] = fir.convert %[[statusResult32]] : (i32) -> i64 ! CHECK: fir.store %[[statusResult]] to %[[status]] : !fir.ref -! CHECK-64: %[[numCast:.*]] = fir.convert %[[numUnboxed]] : (i64) -> i32 -! CHECK-32: %[[lengthResult64:.*]] = fir.call @_FortranAArgumentLength(%[[numUnboxed]]) : (i32) -> i64 -! CHECK-64: %[[lengthResult:.*]] = fir.call @_FortranAArgumentLength(%[[numCast]]) : (i32) -> i64 -! CHECK-32-NEXT: %[[lengthResult:.*]] = fir.convert %[[lengthResult64]] : (i64) -> i32 -! CHECK-NEXT: fir.store %[[lengthResult]] to %[[length]] : !fir.ref end subroutine all_arguments ! CHECK-LABEL: func @_QPnumber_and_length_only( @@ -61,13 +63,17 @@ end subroutine all_arguments subroutine number_and_length_only(num, length) integer :: num, length call get_command_argument(num, LENGTH=length) -! CHECK-NOT: fir.call @_FortranAArgumentValue ! CHECK: %[[numLoaded:.*]] = fir.load %[[num]] : !fir.ref +! CHECK-NEXT: %[[lengthBoxed:.*]] = fir.embox %[[length]] : (!fir.ref) -> !fir.box +! CHECK-NEXT: %[[value:.*]] = 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 - 6]] : i32 ! CHECK-64: %[[numCast:.*]] = fir.convert %[[numLoaded]] : (i64) -> i32 -! CHECK-32: %[[result64:.*]] = fir.call @_FortranAArgumentLength(%[[numLoaded]]) : (i32) -> i64 -! CHECK-64: %[[result:.*]] = fir.call @_FortranAArgumentLength(%[[numCast]]) : (i32) -> i64 -! CHECK-32-NEXT: %[[result:.*]] = fir.convert %[[result64]] : (i64) -> i32 -! CHECK-NEXT: fir.store %[[result]] to %[[length]] : !fir.ref +! CHECK-NEXT: %[[lengthBuffer:.*]] = fir.convert %[[lengthBoxed]] : (!fir.box) -> !fir.box +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %{{.*}} = fir.call @_FortranAGetCommandArgument(%[[numLoaded]], %[[value]], %[[lengthBuffer]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %{{.*}} = fir.call @_FortranAGetCommandArgument(%[[numCast]], %[[value]], %[[lengthBuffer]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 end subroutine number_and_length_only ! CHECK-LABEL: func @_QPnumber_and_status_only( @@ -77,13 +83,16 @@ subroutine number_and_status_only(num, status) call get_command_argument(num, STATUS=status) ! CHECK: %[[numLoaded:.*]] = fir.load %[[num]] : !fir.ref ! 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(@_QQcl{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 6]] : i32 ! CHECK-64: %[[numCast:.*]] = fir.convert %[[numLoaded]] : (i64) -> i32 -! CHECK-32-NEXT: %[[result:.*]] = fir.call @_FortranAArgumentValue(%[[numLoaded]], %[[value]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 -! CHECK-64-NEXT: %[[result32:.*]] = fir.call @_FortranAArgumentValue(%[[numCast]], %[[value]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %[[result:.*]] = fir.call @_FortranAGetCommandArgument(%[[numLoaded]], %[[value]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %[[result32:.*]] = fir.call @_FortranAGetCommandArgument(%[[numCast]], %[[value]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 ! CHECK-64: %[[result:.*]] = fir.convert %[[result32]] : (i32) -> i64 ! CHECK-32: fir.store %[[result]] to %[[status]] : !fir.ref -! CHECK-NOT: fir.call @_FortranAArgumentLength end subroutine number_and_status_only ! CHECK-LABEL: func @_QPnumber_and_errmsg_only( @@ -97,9 +106,12 @@ subroutine number_and_errmsg_only(num, errmsg) ! CHECK-NEXT: %[[numUnboxed:.*]] = fir.load %[[num]] : !fir.ref ! CHECK-NEXT: %[[errmsgBoxed:.*]] = fir.embox %[[errmsgUnboxed]]#0 typeparams %[[errmsgLength]] : (!fir.ref>, index) -> !fir.box> ! CHECK-NEXT: %[[value:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[length:.*]] = fir.absent !fir.box +! CHECK-NEXT: %[[sourceFileString:.*]] = fir.address_of(@_QQcl{{.*}}) : !fir.ref> +! CHECK-NEXT: %[[sourceLine:.*]] = arith.constant [[# @LINE - 8]] : i32 ! CHECK-64: %[[numCast:.*]] = fir.convert %[[numUnboxed]] : (i64) -> i32 ! CHECK-NEXT: %[[errmsg:.*]] = fir.convert %[[errmsgBoxed]] : (!fir.box>) -> !fir.box -! CHECK-32-NEXT: %{{[0-9]+}} = fir.call @_FortranAArgumentValue(%[[numUnboxed]], %[[value]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 -! CHECK-64-NEXT: %{{[0-9]+}} = fir.call @_FortranAArgumentValue(%[[numCast]], %[[value]], %[[errmsg]]) : (i32, !fir.box, !fir.box) -> i32 -! CHECK-NOT: fir.call @_FortranAArgumentLength +! CHECK-NEXT: %[[sourceFile:.*]] = fir.convert %[[sourceFileString]] : (!fir.ref>) -> !fir.ref +! CHECK-32-NEXT: %{{[0-9]+}} = fir.call @_FortranAGetCommandArgument(%[[numUnboxed]], %[[value]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 +! CHECK-64-NEXT: %{{[0-9]+}} = fir.call @_FortranAGetCommandArgument(%[[numCast]], %[[value]], %[[length]], %[[errmsg]], %[[sourceFile]], %[[sourceLine]]) : (i32, !fir.box, !fir.box, !fir.box, !fir.ref, i32) -> i32 end subroutine number_and_errmsg_only diff --git a/flang/test/Runtime/no-cpp-dep.c b/flang/test/Runtime/no-cpp-dep.c index 0f99ccc95e60..259851615674 100644 --- a/flang/test/Runtime/no-cpp-dep.c +++ b/flang/test/Runtime/no-cpp-dep.c @@ -22,15 +22,13 @@ double RTNAME(CpuTime)(); void RTNAME(ProgramStart)(int, const char *[], const char *[]); int32_t RTNAME(ArgumentCount)(); -int32_t RTNAME(ArgumentValue)( - int32_t, const struct Descriptor *, const struct Descriptor *); -int64_t RTNAME(ArgumentLength)(int32_t); +int32_t RTNAME(GetCommandArgument)(int32_t, const struct Descriptor *, + const struct Descriptor *, const struct Descriptor *); int main() { double x = RTNAME(CpuTime)(); RTNAME(ProgramStart)(0, 0, 0); int32_t c = RTNAME(ArgumentCount)(); - int32_t v = RTNAME(ArgumentValue)(0, 0, 0); - int32_t l = RTNAME(ArgumentLength)(0); - return x + c + l; + int32_t v = RTNAME(GetCommandArgument)(0, 0, 0, 0); + return x + c + v; } diff --git a/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp b/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp index 856e2022b93e..28dad42e64c8 100644 --- a/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp +++ b/flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp @@ -17,27 +17,19 @@ TEST_F(RuntimeCallTest, genCommandArgumentCountTest) { /*addLocArgs=*/false); } -TEST_F(RuntimeCallTest, genArgumentValue) { +TEST_F(RuntimeCallTest, genGetCommandArgument) { mlir::Location loc = firBuilder->getUnknownLoc(); mlir::Type intTy = firBuilder->getDefaultIntegerType(); - mlir::Type charTy = fir::BoxType::get(firBuilder->getNoneType()); + mlir::Type boxTy = fir::BoxType::get(firBuilder->getNoneType()); mlir::Value number = firBuilder->create(loc, intTy); - mlir::Value value = firBuilder->create(loc, charTy); - mlir::Value errmsg = firBuilder->create(loc, charTy); - mlir::Value result = - fir::runtime::genArgumentValue(*firBuilder, loc, number, value, errmsg); - checkCallOp(result.getDefiningOp(), "_FortranAArgumentValue", /*nbArgs=*/3, - /*addLocArgs=*/false); -} - -TEST_F(RuntimeCallTest, genArgumentLen) { - mlir::Location loc = firBuilder->getUnknownLoc(); - mlir::Type intTy = firBuilder->getDefaultIntegerType(); - mlir::Value number = firBuilder->create(loc, intTy); - mlir::Value result = - fir::runtime::genArgumentLength(*firBuilder, loc, number); - checkCallOp(result.getDefiningOp(), "_FortranAArgumentLength", /*nbArgs=*/1, - /*addLocArgs=*/false); + mlir::Value value = firBuilder->create(loc, boxTy); + mlir::Value length = firBuilder->create(loc, boxTy); + mlir::Value errmsg = firBuilder->create(loc, boxTy); + mlir::Value result = fir::runtime::genGetCommandArgument( + *firBuilder, loc, number, value, length, errmsg); + checkCallOp(result.getDefiningOp(), "_FortranAGetCommandArgument", + /*nbArgs=*/4, + /*addLocArgs=*/true); } TEST_F(RuntimeCallTest, genEnvVariableValue) { diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp index 85f04267edd3..b44679cd9c51 100644 --- a/flang/unittests/Runtime/CommandTest.cpp +++ b/flang/unittests/Runtime/CommandTest.cpp @@ -105,11 +105,11 @@ protected: SCOPED_TRACE(n); SCOPED_TRACE("Checking argument:"); CheckValue( - [&](const Descriptor *value, const Descriptor *, + [&](const Descriptor *value, const Descriptor *length, const Descriptor *errmsg) { - return RTNAME(ArgumentValue)(n, value, errmsg); + return RTNAME(GetCommandArgument)(n, value, length, errmsg); }, - expectedValue); + expectedValue, std::strlen(expectedValue)); } void CheckCommandValue(const char *args[], int n) const { @@ -162,13 +162,19 @@ protected: OwningPtr value{CreateEmptyCharDescriptor()}; ASSERT_NE(value, nullptr); + OwningPtr length{EmptyIntDescriptor()}; + ASSERT_NE(length, nullptr); + OwningPtr err{errStr ? CreateEmptyCharDescriptor() : nullptr}; - EXPECT_GT(RTNAME(ArgumentValue)(n, value.get(), err.get()), 0); + EXPECT_GT( + RTNAME(GetCommandArgument)(n, value.get(), length.get(), err.get()), 0); std::string spaces(value->ElementBytes(), ' '); CheckDescriptorEqStr(value.get(), spaces); + CheckDescriptorEqInt(length.get(), 0); + if (errStr) { std::string paddedErrStr(GetPaddedStr(errStr, err->ElementBytes())); CheckDescriptorEqStr(err.get(), paddedErrStr); @@ -215,14 +221,10 @@ protected: TEST_F(ZeroArguments, ArgumentCount) { EXPECT_EQ(0, RTNAME(ArgumentCount)()); } -TEST_F(ZeroArguments, ArgumentLength) { - EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); - EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); - EXPECT_EQ(0, RTNAME(ArgumentLength)(1)); -} - -TEST_F(ZeroArguments, ArgumentValue) { +TEST_F(ZeroArguments, GetCommandArgument) { + CheckMissingArgumentValue(-1); CheckArgumentValue(commandOnlyArgv[0], 0); + CheckMissingArgumentValue(1); } TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); } @@ -235,16 +237,11 @@ protected: TEST_F(OneArgument, ArgumentCount) { EXPECT_EQ(1, RTNAME(ArgumentCount)()); } -TEST_F(OneArgument, ArgumentLength) { - EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); - EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); - EXPECT_EQ(20, RTNAME(ArgumentLength)(1)); - EXPECT_EQ(0, RTNAME(ArgumentLength)(2)); -} - -TEST_F(OneArgument, ArgumentValue) { +TEST_F(OneArgument, GetCommandArgument) { + CheckMissingArgumentValue(-1); CheckArgumentValue(oneArgArgv[0], 0); CheckArgumentValue(oneArgArgv[1], 1); + CheckMissingArgumentValue(2); } TEST_F(OneArgument, GetCommand) { CheckCommandValue(oneArgArgv, 2); } @@ -262,17 +259,7 @@ TEST_F(SeveralArguments, ArgumentCount) { EXPECT_EQ(4, RTNAME(ArgumentCount)()); } -TEST_F(SeveralArguments, ArgumentLength) { - EXPECT_EQ(0, RTNAME(ArgumentLength)(-1)); - EXPECT_EQ(8, RTNAME(ArgumentLength)(0)); - EXPECT_EQ(16, RTNAME(ArgumentLength)(1)); - EXPECT_EQ(0, RTNAME(ArgumentLength)(2)); - EXPECT_EQ(22, RTNAME(ArgumentLength)(3)); - EXPECT_EQ(1, RTNAME(ArgumentLength)(4)); - EXPECT_EQ(0, RTNAME(ArgumentLength)(5)); -} - -TEST_F(SeveralArguments, ArgumentValue) { +TEST_F(SeveralArguments, GetCommandArgument) { CheckArgumentValue(severalArgsArgv[0], 0); CheckArgumentValue(severalArgsArgv[1], 1); CheckArgumentValue(severalArgsArgv[3], 3); @@ -280,10 +267,11 @@ TEST_F(SeveralArguments, ArgumentValue) { } TEST_F(SeveralArguments, NoArgumentValue) { - // Make sure we don't crash if the 'value' and 'error' parameters aren't - // passed. - EXPECT_EQ(RTNAME(ArgumentValue)(2, nullptr, nullptr), 0); - EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, nullptr), 0); + // Make sure we don't crash if the 'value', 'length' and 'error' parameters + // aren't passed. + EXPECT_GT(RTNAME(GetCommandArgument)(2), 0); + EXPECT_EQ(RTNAME(GetCommandArgument)(1), 0); + EXPECT_GT(RTNAME(GetCommandArgument)(-1), 0); } TEST_F(SeveralArguments, MissingArguments) { @@ -296,14 +284,19 @@ TEST_F(SeveralArguments, MissingArguments) { TEST_F(SeveralArguments, ArgValueTooShort) { OwningPtr tooShort{CreateEmptyCharDescriptor<15>()}; ASSERT_NE(tooShort, nullptr); - EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), nullptr), -1); + EXPECT_EQ(RTNAME(GetCommandArgument)(1, tooShort.get()), -1); CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]); + OwningPtr length{EmptyIntDescriptor()}; + ASSERT_NE(length, nullptr); OwningPtr errMsg{CreateEmptyCharDescriptor()}; ASSERT_NE(errMsg, nullptr); - EXPECT_EQ(RTNAME(ArgumentValue)(1, tooShort.get(), errMsg.get()), -1); + EXPECT_EQ( + RTNAME(GetCommandArgument)(1, tooShort.get(), length.get(), errMsg.get()), + -1); + CheckDescriptorEqInt(length.get(), 16); std::string expectedErrMsg{ GetPaddedStr("Value too short", errMsg->ElementBytes())}; CheckDescriptorEqStr(errMsg.get(), expectedErrMsg); @@ -311,7 +304,7 @@ TEST_F(SeveralArguments, ArgValueTooShort) { TEST_F(SeveralArguments, ArgErrMsgTooShort) { OwningPtr errMsg{CreateEmptyCharDescriptor<3>()}; - EXPECT_GT(RTNAME(ArgumentValue)(-1, nullptr, errMsg.get()), 0); + EXPECT_GT(RTNAME(GetCommandArgument)(-1, nullptr, nullptr, errMsg.get()), 0); CheckDescriptorEqStr(errMsg.get(), "Inv"); }