Index: flang/include/flang/Optimizer/Builder/Runtime/Command.h =================================================================== --- flang/include/flang/Optimizer/Builder/Runtime/Command.h +++ flang/include/flang/Optimizer/Builder/Runtime/Command.h @@ -23,19 +23,13 @@ /// 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 GetArgumentValue 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. Index: flang/include/flang/Runtime/command.h =================================================================== --- flang/include/flang/Runtime/command.h +++ flang/include/flang/Runtime/command.h @@ -32,17 +32,12 @@ 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 Index: flang/lib/Lower/IntrinsicCall.cpp =================================================================== --- flang/lib/Lower/IntrinsicCall.cpp +++ flang/lib/Lower/IntrinsicCall.cpp @@ -768,7 +768,7 @@ &I::genGetCommandArgument, {{{"number", asValue}, {"value", asBox, handleDynamicOptional}, - {"length", asAddr}, + {"length", asBox, handleDynamicOptional}, {"status", asAddr}, {"errmsg", asBox, handleDynamicOptional}}}, /*isElemental=*/false}, @@ -2776,38 +2776,32 @@ 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(); } } Index: flang/lib/Optimizer/Builder/Runtime/Command.cpp =================================================================== --- flang/lib/Optimizer/Builder/Runtime/Command.cpp +++ flang/lib/Optimizer/Builder/Runtime/Command.cpp @@ -32,27 +32,19 @@ 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( Index: flang/runtime/command.cpp =================================================================== --- flang/runtime/command.cpp +++ flang/runtime/command.cpp @@ -37,15 +37,6 @@ } } -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,48 +98,71 @@ return stat; } -std::int32_t RTNAME(ArgumentValue)( - std::int32_t n, const Descriptor *value, const Descriptor *errmsg) { - if (IsValidCharDescriptor(value)) { +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 { + bool operator()(std::int64_t value) { + return value <= std::numeric_limits>::max(); + } +}; + +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}; + + 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); } - if (IsValidCharDescriptor(value)) { - const char *arg{executionEnvironment.argv[n]}; - std::int64_t argLen{StringLength(arg)}; - if (argLen <= 0) { - return ToErrmsg(errmsg, StatMissingArgument); - } + 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; } -template struct FitsInIntegerKind { - bool operator()(std::int64_t value) { - return value <= std::numeric_limits>::max(); - } -}; - std::int32_t RTNAME(GetCommand)(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)); } @@ -156,7 +170,7 @@ // 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 @@ } } - 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 Index: flang/test/Lower/Intrinsics/get_command_argument-optional.f90 =================================================================== --- flang/test/Lower/Intrinsics/get_command_argument-optional.f90 +++ flang/test/Lower/Intrinsics/get_command_argument-optional.f90 @@ -19,25 +19,25 @@ ! 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 Index: flang/test/Lower/Intrinsics/get_command_argument.f90 =================================================================== --- flang/test/Lower/Intrinsics/get_command_argument.f90 +++ 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 @@ ! 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 @@ ! 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 @@ 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 @@ 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 @@ ! 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 Index: flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp =================================================================== --- flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp +++ flang/unittests/Optimizer/Builder/Runtime/CommandTest.cpp @@ -17,27 +17,19 @@ /*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) { Index: flang/unittests/Runtime/CommandTest.cpp =================================================================== --- flang/unittests/Runtime/CommandTest.cpp +++ flang/unittests/Runtime/CommandTest.cpp @@ -105,11 +105,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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, 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, 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, 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"); }